from typing import Any, Dict, Tuple, Optional
from urllib.parse import urlparse

from starwhale.utils import config
from starwhale.base.uri.exceptions import NoMatchException

def _get_instances() -> Dict[str, Dict]:
    return config.load_swcli_config().get("instances", {})  # type: ignore[no-any-return]

def _get_default_instance_alias() -> str:
    return config.load_swcli_config().get("current_instance", "")  # type: ignore[no-any-return]

def _find_alias_by_url(url: str, token: Optional[str] = None) -> Tuple[str, str]:
    """parse url and return instance alias and path from url"""
    if not url:
        return _get_default_instance_alias(), ""
    inst_uri_map = {name: conf["uri"] for name, conf in _get_instances().items()}
    inst_names = list(inst_uri_map.keys())

    # fast path if url is alias
    if url in inst_names:
        return url, ""

    p = urlparse(url)
    ins_url = "://".join([p.scheme, p.netloc])
    if token is not None:
        return "tmp", url
    # use host as alias when url starts with cloud or non-scheme
    if p.scheme == "cloud":
        if p.netloc not in inst_uri_map:
            raise NoMatchException(p.netloc, inst_names)
        return p.netloc, p.path
    elif p.scheme == "":
        netloc, path = url.split("/", 1)
        if netloc not in inst_uri_map:
            raise NoMatchException(netloc, inst_names)
        return netloc, path
    else:
        hits = [name for name, uri in inst_uri_map.items() if uri == ins_url]
        if len(hits) == 1:
            return hits[0], p.path
        raise NoMatchException(url, hits)

def _check_alias_exists(alias: str) -> None:
    if alias not in _get_instances():
        raise NoMatchException(alias)

class Instance:
    """
    Data structure for Instance info
    """

    alias: str
    path: str = ""

    def __init__(
        self,
        uri: str = "",
        instance_alias: Optional[str] = None,
        token: Optional[str] = None,
    ) -> None:
        self._info: Dict[str, Any] = {}
        if instance_alias and uri:
            raise Exception("alias and uri can not both set")
        if not instance_alias:
            instance_alias, path = _find_alias_by_url(uri, token)
            self.path = path.strip("/")
        if token is None:
            _check_alias_exists(instance_alias)
        else:
            self._info = {"sw_token": token, "uri": path, "type": "cloud"}
        self.alias = instance_alias

    @property
    def info(self) -> Dict[str, str]:
        """Get current instance info"""
        return self._info or _get_instances().get(self.alias, {})

    @property
    def url(self) -> str:
        return self.info.get("uri", "")

    @property
    def type(self) -> str:
        return self.info.get("type", "")

    @property
    def username(self) -> str:
        return self.info.get("username", "")

    @property
    def token(self) -> str:
        return self.info.get("sw_token", "")

    @property
    def is_local(self) -> bool:
        return self.url == "local"

    @property
    def is_cloud(self) -> bool:
        return not self.is_local

    def __str__(self) -> str:
        if self.is_local:
            return self.url
        return f"cloud://{self.alias}"


#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#
# @name   : PhoneInfoga - Phone numbers OSINT tool
# @url    : https://github.com/sundowndev
# @author : Raphael Cerveaux (sundowndev)

from bs4 import BeautifulSoup
import hashlib
import json
from lib.output import *
from lib.request import send

'''
Scanning phone number
return:
 0: Success
-1: phone number format error. Error: Please specify a valid phone number. Example: +6464806649
-2: connection error to https://numverify.com/
'''
def scan(number, proxy):

    #test('Running Numverify.com scan...')

    try:
        requestSecret = ''
        res = send('GET', 'https://numverify.com/', {}, proxy)
        soup = BeautifulSoup(res.text, "html5lib")
    except Exception as e:
        error('Numverify.com is not available')
        #error(e)
        return -2, {'valid':False}

    for tag in soup.find_all("input", type="hidden"):
        if tag['name'] == "scl_request_secret":
            requestSecret = tag['value']
            break

    apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest()

    headers = {
        'Host': 'numverify.com',
        'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Language': 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3',
        'Accept-Encoding': 'gzip, deflate, br',
        'Referer': 'https://numverify.com/',
        'X-Requested-With': 'XMLHttpRequest',
        'DNT': '1',
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache'
    }

    try:
        res = send("GET", "https://numverify.com/php_helper_scripts/phone_api.php?secret_key={}&number={}".format(apiKey, number), headers, proxy)
        data = json.loads(res.content.decode('utf-8'))
    except Exception as e:
        #error('Numverify.com is not available')
        return -2, {'valid':False}

    if res.content == "Unauthorized" or res.status_code != 200:
        #error(("An error occured while calling the API (bad request or wrong api key)."))
        return -2, {'valid':False}

    if 'error' in data:
        #error('Numverify.com is not available: ' + data['error'])
        return -2, {'valid':False}

    return 0, data


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import argparse
import numpy as np
import networkx as nx
import subprocess
import os
from tulip import tlp
import pandas as pd
from evalne.utils import preprocess as pp

def parse_args():
    """ Parses Fruchterman-Reingold arguments."""

    parser = argparse.ArgumentParser(
        description="Run force-based Fruchterman-Reingold algorithm."
    )

    parser.add_argument("--inputgraph", nargs="?", help="Input graph path")

    parser.add_argument(
        "--output",
        nargs="?",
        default=None,
        help="Path where the embeddings will be stored.",
    )

    parser.add_argument(
        "--dimension", type=int, default=2, help="Embedding dimension. Default is 2."
    )

    parser.add_argument(
        "--epochs", type=int, default=100, help="Training epochs. Default is 100."
    )

    parser.add_argument(
        "--delimiter", default=",", help="The delimiter used to separate the edgelist."
    )

    parser.add_argument(
        "--mode",
        default="rtx",
        type=str,
        choices=["networkx", "rtx", "naive", "lbvh"],
        help="Choose FR implementation. Networkx = networkx.spring_layout and rtx as \
        well as lbvh and naive use the owl-graph-drawing implementation",
    )

    parser.add_argument(
        "--exec",
        type=str,
        default="methods/frrtx/build/gd",
        help="Path where the executable 'gd' can be found.",
    )
    return parser.parse_args()

def tulip2txt(input, output, delimiter=","):
    """
    https://tulip.labri.fr/Documentation/current/tulip-python/html/tulippluginsdocumentation.html#csv-export
    """

    tmp_tlp_output = os.path.join(os.path.split(output)[0], "tmp_tlp_output.csv")

    # read tlp file
    params = tlp.getDefaultPluginParameters("TLP Import")
    params["filename"] = input
    graph = tlp.importGraph("TLP Import", params)

    # export layout properties to csv
    params = tlp.getDefaultPluginParameters("CSV Export", graph)
    params["Field separator"] = "Custom"
    params["Custom separator"] = ";"
    params["Type of elements"] = "nodes"
    params["Export id"] = True
    params["Export visual properties"] = True
    tlp.exportGraph("CSV Export", graph, tmp_tlp_output, params)

    # read tmp export and extract coordinates
    tlp_graph = pd.read_table(tmp_tlp_output, delimiter=";")
    coordinates = tlp_graph["viewLayout"].values
    coordinates = [
        [float(tp.strip("()").split(",")[0]), float(tp.strip("()").split(",")[1])]
        for tp in coordinates
    ]
    np.savetxt(output, coordinates, delimiter=delimiter)

    # delete temporary file
    if os.path.isfile(tmp_tlp_output):
        os.remove(tmp_tlp_output)

def tulip2edgestxt(input, output, delimiter=","):
    """
    https://tulip.labri.fr/Documentation/current/tulip-python/html/tulippluginsdocumentation.html#csv-export
    """

    tmp_tlp_output = os.path.join(os.path.split(output)[0], "tmp_tlp_output.csv")

    # read tlp file
    params = tlp.getDefaultPluginParameters("TLP Import")
    params["filename"] = input
    graph = tlp.importGraph("TLP Import", params)

    # export layout properties to csv
    params = tlp.getDefaultPluginParameters("CSV Export", graph)
    params["Field separator"] = "Custom"
    params["Custom separator"] = ";"
    params["Type of elements"] = "edges"
    params["Export id"] = True
    params["Export visual properties"] = False
    tlp.exportGraph("CSV Export", graph, tmp_tlp_output, params)

    # read tmp export and extract coordinates
    tlp_graph = pd.read_table(tmp_tlp_output, delimiter=";")
    src = tlp_graph["src id"].values
    target = tlp_graph["tgt id"].values
    np.savetxt(output, np.transpose(np.array([src, target])), delimiter=delimiter, fmt="%i")

    # delete temporary file
    if os.path.isfile(tmp_tlp_output):
        os.remove(tmp_tlp_output)

def run_RT_FR(input_file, output_file, delimiter, epochs, exec, mode):
    # the implementation needs a header for the edgelist input file
    edges = np.loadtxt(input_file, delimiter=",", dtype=int)

    # transform file into csv with header
    tmp_rtx_edgefle = os.path.join(os.path.split(input_file)[0], "tmp_rtx_edgefile.csv")
    np.savetxt(tmp_rtx_edgefle, edges, delimiter=",", fmt="%i", header="edgelist")

    tmp_tulip_output = os.path.join(os.path.split(output_file)[0], "tmp_tulip.tlp")

    start = time.time()
    process = subprocess.Popen(
        [
            exec,
            "-bench=true",
            "-dt=file",
            "-mode=" + mode,
            "-n=" + str(epochs),
            "-o=" + tmp_tulip_output,
            tmp_rtx_edgefle,
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        encoding="utf8"
    )

    while True:
        if process.poll() is not None:
            break
        output = process.stdout.readline()
        if output:
            dec_output = output.strip()
            if "done" in dec_output:
                break

    runtime = time.time() - start
    print(f"Embedding time: {runtime:.4f}")

    assert os.path.isfile(tmp_tulip_output), f"FR-RTX did not produce the output file {tmp_tulip_output}."
    process.terminate()

    # convert tlp into txt embedding
    tulip2txt(tmp_tulip_output, output_file, delimiter)

    # write out edges from tulip
    tmp_tulip_edgefile = "tmp_tlp_edges.txt"
    tulip2edgestxt(tmp_tulip_output, tmp_tulip_edgefile, delimiter)
    tlp_edges = np.loadtxt(tmp_tulip_edgefile, delimiter=",", dtype=int)

    embedding = np.loadtxt(output_file, delimiter=delimiter)

    if not (edges == tlp_edges).all():
        print("Nodes are relabeled by FR-RTX. Computing node mapping.")
        # edgelists are not the same -- so node IDs should be in different order
        flat_edges = edges.flatten()
        indexes = np.unique(edges.flatten(), return_index=True)[1]
        unique_edges = [flat_edges[index] for index in sorted(indexes)]
        node_order = np.argsort(unique_edges)
        embedding = embedding[node_order]

    if os.path.isfile(tmp_tulip_output):
        os.remove(tmp_tulip_output)
    if os.path.isfile(tmp_tulip_edgefile):
        os.remove(tmp_tulip_edgefile)
    if os.path.isfile(tmp_rtx_edgefle):
        os.remove(tmp_rtx_edgefle)

    np.savetxt(output_file, embedding, delimiter=delimiter)

    return float(runtime)

def spring_layout(input_file, output_file, delimiter, epochs):
    G = pp.load_graph(input_file, delimiter=delimiter)
    G, _ = pp.prep_graph(G)

    # Compute Fruchterman-Reingold layout
    start = time.time()
    embedding_dict = nx.spring_layout(G, iterations=epochs)
    runtime = time.time() - start
    print(f"Embedding time: {runtime:.4f}")
    embedding_dict = dict(sorted(embedding_dict.items(), key=lambda item: item[0]))
    embedding = np.array(list(embedding_dict.values()))

    # Store the embedding in output file
    np.savetxt(output_file, embedding, delimiter=delimiter)

def main(args):
    # Naive spring layout implementation
    if args.mode == "networkx" or not os.path.isfile(args.exec):
        spring_layout(args.inputgraph, args.output, args.delimiter, args.epochs)

    # Use faster owl-graph-drawing implementation
    else:
        run_RT_FR(
            args.inputgraph,
            args.output,
            args.delimiter,
            args.epochs,
            args.exec,
            args.mode,
        )

if __name__ == "__main__":
    args = parse_args()
    main(args)


from sys import argv, exit
from collections import OrderedDict
from functools import reduce
import re
import httplib2

# Google API
from apiclient import discovery
from apiclient.errors import HttpError
from oauth2client import client, tools
from oauth2client.file import Storage

# Reddit API
import praw
import OAuth2Util

#
# Configuration.
#

# The ID of the spreadsheet, which can be found in the URL. This example is the
# ID for https://docs.google.com/spreadsheets/d/1v8SVnzrGaupBKm6CbtmPjMqOrkcl0_sfEW0eEcujkys/edit
SPREADSHEET_ID = "1v8SVnzrGaupBKm6CbtmPjMqOrkcl0_sfEW0eEcujkys"
# The flair sheet is the sheet where the username, mail, snail mail and flair
# assignment columns are. The bot assumes these columns are given in this order
# starting in column A and the actual values start in row 2.
FLAIR_SHEET = "Sheet1"
# This bot will store the timestamp of the last comment it handled. This way it
# will know which comments have already been handled. This reference will
# be stored in the cell indicated here. See
# https://developers.google.com/sheets/guides/concepts#a1_notation to know how
# to reference cells. You can always hide these in a hidden sheet if you prefer
# them not being visible on the main sheet.
PREV_COMMENT_TIME_CELL = FLAIR_SHEET+"!J2"
# The bot will also store a reference to the previous thread it processed, this
# way it can handle any new comments in the old sticky before going to the new
# one. It will also make it easy for the bot to know when the "prev comment"
# value is no longer relevant, as the sticky thread changed.
PREV_THREAD_ID_CELL = FLAIR_SHEET+"!I2"
# if a user tries to enter a high combined verification count for a single user,
# the bot will not automatically update the count, but send an email to the
# moderators instead. E.g. with a threshold of 30, "/u/user 20 20" will not
# automatically be added, but will cause a mail to be sent to the mods instead.
COUNT_THRESHOLD_USER = 10
# The same as before, except it will look if the total verification count of a
# comment is high, instead of just the verified count for a single user.
COUNT_THRESHOLD_COMMENT = 30
# A list of mods that will be mailed if the bot encounters something fishy. If
# the list is empty, no mods will be mailed. Usernames are always written
# without the /u/ part. To send to all moderators of a subreddit, write
# /r/subreddit_name
#MODS = ["wmeacham", ]
#MODS = ["/r/penpals", ]
MODS = ["/r/BitwiseShiftTest"]
# A definition of all ranks in descending order of prestige. The first value
# must be the flair CSS class, the second is a function determining whether
# a user has met the conditions for this flair. I guessed these, change them
# to their actual values! The requirements function gets passed a row from the
# datasheet, whose values are all strings.
RANKS = OrderedDict([
	("combogold", lambda row: int(row[1]) >= 300 and int(row[2]) >= 100),
	("goldsnail", lambda row: int(row[1]) >= 300 or int(row[2]) >= 100),
	("combosilver", lambda row: int(row[1]) >= 30 and int(row[2]) >= 10),
	("silversnail", lambda row: int(row[1]) >= 30 or int(row[2]) >= 10),
	("combobronze", lambda row: int(row[1]) >= 3 and int(row[2]) >= 1),
	("bronzeemail", lambda row: int(row[1]) >= 3 or int(row[2]) >= 1),
	("", lambda row: True),	# Catch-all, for people who have not met any requirements yet.
])
# Wether to allow users to verify themselves.
ALLOW_SELF_VERIFICATION = False

#
# Actual bot code
#

# Read configuration file if one is given.
if len(argv) == 2:
	try:
		with open(argv[1], "r") as f:
			exec(f.read())
	except FileNotFoundError as e:
		print("[ERROR] The config file could not be found.")
		raise e
	except Exception as e:
		print("[ERROR] The config file contains error.")
		raise e
elif len(argv) > 2:
	print("[Error] Correct syntax: {} [config_file]".format(argv[0]))
	exit()

class colors:
	# Adapted from https://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python
	OK = "\033[92m\033[1m"
	WARNING = "\033[93m\033[1m"
	ERROR = "\033[91m\033[1m"
	INPUT = "\033[94m\033[1m"
	ENDC = "\033[0m"

def get_credentials():
	"""	Gets valid user credentials from storage.
		If nothing has been stored, or if the stored credentials are invalid,
		the OAuth2 flow is completed to obtain the new credentials.

		Returns:
		Credentials, the obtained credential.
	"""
	store = Storage("sheets.googleapis.com-python-penpalsbot.json")
	credentials = store.get()
	if not credentials or credentials.invalid:
		flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
		flow.user_agent = APPLICATION_NAME
		credentials = tools.run_flow(flow, store)
	return credentials

def get_verification_thread():
	print("Looking for new verification sticky...")
	print("Checking top sticky...", end="")
	sticky = r.get_sticky(SUBREDDIT, True)
	if "verification post" not in sticky.title.lower():
		print("\nChecking bottom sticky...", end="")
		sticky = r.get_sticky(SUBREDDIT, False)
		if "verification post" not in sticky.title.lower():
			sticky = None
	print(colors.OK+" DONE"+colors.ENDC)
	return sticky

def message_mods(subject, message):
	""" Lazy loaded send mods a message. """
	return
	global MODS
	for mod in MODS:
		try:
			r.send_message(mod, subject, message, from_sr=SUBREDDIT)
		except praw.errors.Forbidden:
			print(colors.WARNING+"[WARNING]"+colors.ENDC+" Unable to send a message to /u/{}".format(mod))

def expand_comments(thread):
	""" Expand top-level comments to the point where there are no more comments.
		Returned comments are sorted descendingly by time.
	"""
	comments = list(thread.comments)
	oldLen = 0
	newLen = len(comments)
	while newLen != oldLen:
		oldLen = newLen
		thread.replace_more_comments()
		comments = list(thread.comments)
		newLen = len(comments)
	comments.sort(key=lambda x: int(x.created_utc), reverse=True)
	return comments

def total_verification_count(verifications):
	return reduce(lambda a, x: a + int(x["mail_count"]) + int(x["letter_count"]), verifications, 0)

def process_comments(thread, prev_comment_time=0):
	""" Process comments for verification strings.
		Returns the UTC timestamp of the last processed comment. If no new
		comments were found, returns None.
	"""
	comments = expand_comments(thread)
	if not comments or int(comments[0].created_utc) <= prev_comment_time:
		print("No new comments found.")
		return None
	for comment in comments:
		if int(comment.created_utc) <= prev_comment_time:
			break
		print("+ Handling new comment. ID={}".format(comment.id))
		verifications = []	# Stores all verifications of a comment until it is processed.
		error_occurred = False
		# Start looking for verification count strings.
		paragraphs = comment.body.splitlines()
		for paragraph in paragraphs:
			match = RE_VERIFICATION_SYNTAX.match(paragraph)
			if match:
				print("... Verification count string found: "+paragraph)
				# Add user to added_count if he wasn't in there yet.
				data = match.groupdict()
				if not ALLOW_SELF_VERIFICATION and comment.author.name == data["username"]:
					print("... "+colors.WARNING+"[WARNING]"+colors.ENDC+" Trying to verify himself. Ignoring and messaging mods.")
					message_mods("Self-verification", """
					It appears [a user]({}) is attempting to verify themselves.
					This comment has been ignored and will have to be manually
					verified.
					""".format(comment.permalink))
					error_occurred = True
					break
				data["mail_count"] = int(data["mail_count"])
				data["letter_count"] = int(data["letter_count"])
				# Check if the COUNT_THRESHOLD_USER hasn't been exceeded.
				if data["mail_count"] + data["letter_count"] >= COUNT_THRESHOLD_USER:
					print("... "+colors.WARNING+"[WARNING]"+colors.ENDC+" High verification count for a single user. Ignoring and messaging mods.")
					message_mods("Verification count threshold exceeded", """
					It appears [a comment]({}) is attempting to verify a large
					email and/or letter count for a single user. This comment
					has been ignored and will have to be manually verified.
					""".format(comment.permalink))
					error_occurred = True
					break
				else:
					verifications.append(data)
		# Only verify the comment threshold id the user threshold wasn't exceeded.
		if not error_occurred:
			# Check the comment threshold.
			if total_verification_count(verifications) > COUNT_THRESHOLD_COMMENT:
				print("... "+colors.WARNING+"[WARNING]"+colors.ENDC+" High verification count for a single user. Ignoring and messaging mods.")
				message_mods("Verification count threshold exceeded", """
				It appears [a comment]({}) is attempting to verify a large
				email and/or letter count for a single user. This comment
				has been ignored and will have to be manually verified.
				""")
			else:
				# No errors, apply the verification counts.
				for data in verifications:
					global added_count
					if data["username"] not in added_count:
						added_count[data["username"]] = {"mail_count": 0, "letter_count": 0}
					added_count[data["username"]]["mail_count"] += data["mail_count"]
					added_count[data["username"]]["letter_count"] += data["letter_count"]
	return int(comments[-1].created_utc)

def get_flair_css_class(spreadsheet_row):
	for flair_css_class, requirement_fun in RANKS.items():
		if requirement_fun(spreadsheet_row):
			return flair_css_class

def recompute_spreadsheet_data(spreadsheet_data, added_count):
	""" Recomputes all values in the spreadsheet.
		Returns all flairs that changed during the recompute in the form
		[{username: string, flair: string}]
	"""
	changed_flairs = {}		# Will contain values {username: flairstring}
	for i, (username, mail_count, letter_count, flair_class) in enumerate(spreadsheet_data[1:], 1):
		if username[3:] in added_count:
			spreadsheet_data[i][1] = str(int(spreadsheet_data[i][1]) + added_count[username[3:]]["mail_count"])
			spreadsheet_data[i][2] = str(int(spreadsheet_data[i][2]) + added_count[username[3:]]["letter_count"])
			new_flair_class = get_flair_css_class(spreadsheet_data[i])
			# Only bother updating flairs that changed, paying special attention to n/a's that are non-existant flair classes.
			if new_flair_class != flair_class and not (not new_flair_class and flair_class == "n/a"):
				spreadsheet_data[i][3] = new_flair_class
				changed_flairs[username[3:]] = new_flair_class
			del added_count[username[3:]]
	# Append all users that haven't been handled yet to the end of the spreadsheet.
	for username, counts in added_count.items():
		new_flair_class = get_flair_css_class(spreadsheet_data[i])
		changed_flairs[username[3:]] = new_flair_class
		spreadsheet_data.append(["/u/"+username, counts["mail_count"], counts["letter_count"], new_flair_class])
	return changed_flairs

def update_flairs(changed_flairs):
	print("Updating flairs...")
	after = None

	flairs = []
	unknowns = []
	# Update existing flairs.
	for username, flair_css_class in changed_flairs.items():
		print("... /u/{} <- {}".format(username, flair_css_class))
		try:
			flair = r.get_flair(SUBREDDIT, username)
		except praw.errors.Forbidden:
			print(colors.ERROR+"[ERROR]"+colors.ENDC+" Could not retrieve flair information! Does the bot have mod privileges?".format(username))
			exit()
		if flair == None:
			print(colors.WARNING+"[WARNING]"+colors.ENDC+" /u/{} does not exist!".format(username))
			# TODO: do something more with the knowledge that the user doesn't exists?
			continue
		# The empty flair texts (None) need to be converted to empty strings.
		if flair["flair_css_class"] == None:
			flair["flair_css_class"] = ""
		if flair["flair_text"] == None:
			flair["flair_text"] = ""
		# Validate the flair classes with those defined.
		if flair["flair_css_class"] not in RANKS and flair["flair_css_class"] not in unknowns:
			unknowns.append(flair_css_class)
			print(colors.ERROR+"[ERROR]"+colors.ENDC+' Encountered an unknown CSS flair class "{}".'.format(flair["flair_css_class"]))
		print("... Queuing flair {} for /u/{}".format(flair_css_class, flair["user"]))
		flair["flair_css_class"] = flair_css_class
		flairs.append(flair)
	# Only give a warning the first time an unknown class is encountered.
	if unknowns:
		input(colors.INPUT+"[INPUT NEEDED]"+colors.ENDC+" There were some unknown CSS flair classes!\n"
			"			   This probably means you forgot to define that class.\n"
			"			   Close the progam now and fix the error, or press ENTER\n"
			"			   to continue, ignoring any errors.")
	while flairs:
		# Update flairs.
		to_i = min(flairs.len, 100)
		r.set_flair_csv(SUBREDDIT, flairs[:to_i])
		print("Succesfully changed a section of the user's flairs")
		flairs = flairs[to_i:]
	print(colors.OK+"[SUCCESS]"+colors.ENDC+" Updated all user's flairs")

# Google Sheets API
SCOPES = "https://www.googleapis.com/auth/spreadsheets"
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "Google Sheets API Python Quickstart"
DATA_RANGE = FLAIR_SHEET+"!A:D"
# Global variables
SUBREDDIT = "penpals"
# Regular expressing expressing the syntax of the command.
RE_VERIFICATION_SYNTAX = re.compile(
		r"\A\s*"						# Any leading whitespace.
		# Reddit username, based on the Reddit source code.
		# First / is optional, as people seemed to forget it occasionally.
		# Entire /u/ part can be left out as well.
		r"(/?u/)?(?P<username>[\w\-]+)"
		r"[\s,_\-+]+"					# Delimiters.
		r"(?P<mail_count>[0-9]+)"
		r"[\s,_\-+]+"					# Delimiters.
		r"(?P<letter_count>[0-9+]+)"
		r"\s*\Z",						# Any trailing whitespace.
		re.UNICODE)

print("Authenticating with Docs API...", end="")
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
discoveryUrl = ("https://sheets.googleapis.com/$discovery/rest?version=v4")
service = discovery.build("sheets", "v4", http=http,
 						  discoveryServiceUrl=discoveryUrl)
print(colors.OK+" DONE"+colors.ENDC)

print("Authenticating with Reddit...", end="")
r = praw.Reddit("Python:PenpalsVerification by /u/BitwiseShift")
r.config.api_request_delay = 1.0
o = OAuth2Util.OAuth2Util(r)
o.refresh()
print(colors.OK+" DONE"+colors.ENDC)

# Keeps tracks of added counts per user.
added_count = {}		# Will contain count in the form {username: {mail_count: int, letter_count: int}}.

print("Getting spreadsheet data... ", end="")
prev_thread_id, prev_comment_time, spreadsheet_data = service.spreadsheets().values().batchGet(
		spreadsheetId=SPREADSHEET_ID, ranges=[PREV_THREAD_ID_CELL, PREV_COMMENT_TIME_CELL, DATA_RANGE]).execute()["valueRanges"]
# Set default values.
prev_thread_id = prev_thread_id.get("values", [[None]])[0][0]
prev_comment_time = int(prev_comment_time.get("values", [[0]])[0][0])
spreadsheet_data = spreadsheet_data.get("values", [])
# Pad rows, as Google leaves out empty rows at the end, i.e. empty css class strings.
spreadsheet_data = [row + [""]*(4-len(row)) for row in spreadsheet_data]

if prev_thread_id == None:
	print("No previous thread run found.")
	prev_comment_time = 0
	comment_time1 = None
else:
	print("Checking for new comments in previous thread run...")
	prev_thread = r.get_submission(submission_id=prev_thread_id)
	comment_time1 = process_comments(prev_thread, prev_comment_time)
	prev_comment_time = comment_time1 if comment_time1 else prev_comment_time

sticky = get_verification_thread()
# Check if the sticky was found.
if sticky:
	print("Verification thread found!")
else:
	print("Could not find new the verification thread!")
# Check if the sticky is different from the previous thread we processed.
if sticky.id == prev_thread_id:
	print("The verification thread hasn't changed!")
	comment_time2 = None
else:
	comment_time2 = process_comments(sticky, prev_comment_time)
	prev_comment_time = comment_time2 if comment_time2 else prev_comment_time
	prev_thread_id = sticky.id
# Only continue further if some new comments were found.
if comment_time1 or comment_time2:
	print("Handled all comments!")
	print("Computing new counts and flairs...", end="")
	changed_flairs = recompute_spreadsheet_data(spreadsheet_data, added_count)
	print(colors.OK+" DONE"+colors.ENDC)
	if changed_flairs:
		try:
			update_flairs(changed_flairs)
			print(colors.OK+" DONE"+colors.ENDC)
		except praw.errors.Forbidden:
			print(colors.ERROR+"\n[ERROR]"+colors.ENDC+" Unable to update the user's flairs! Does the bot have mod privileges?")
			exit()
	else:
		print("No flairs changed!")

	print("Writing persistence values to spreadsheet...", end="")
	data = [
		{"range": PREV_THREAD_ID_CELL, "values": [[prev_thread_id]]},
		{"range": PREV_COMMENT_TIME_CELL, "values": [[str(prev_comment_time)]]},
		{"range": DATA_RANGE, "values": spreadsheet_data}
	]
	service.spreadsheets().values().batchUpdate(
		body={"valueInputOption": "USER_ENTERED", "data": data},
		spreadsheetId=SPREADSHEET_ID).execute()
	print(colors.OK+" DONE"+colors.ENDC)
else:
	print("No new comments!")
print(colors.OK+"[SUCCESS]"+colors.ENDC+" Script finished!")


from flask import Flask, render_template, redirect
import pymongo
from flask_pymongo import PyMongo
import scrape_mars

#Spin up the Flask App
app = Flask(__name__, template_folder='templates')

app.config["MONGO_URI"] = "mongodb://localhost:27017/mars_app"
mongo = PyMongo(app)

#Or set inline
#mongo = PyMongo(app, uri="mongodb://localhost:27017/mars_app")

#Creation of connection variable. Connection to local host for local Mongo.
#conn = "mongodb://localhost:27017"

#Pass connection to the pymongo instance"
#client = pymongo.MongoClient(conn)

#Connect to a database. Will create one if not already available
#db = client.redplanet_db
#mars = db.mars_dict

#Drops collection if available to remove dublicates
#db.mars_dict.drop()

#Mongo Creates Collection automatically
#db.mars_dict.inset_many()#insert list of dict

#App Route
@app.route("/")
def index():
    mars = mongo.db.mars.find_one()
    return render_template("index.html", data=mars)

@app.route("/scrape")
def scraper():
    mars = mongo.db.mars
    mars_data = scrape_mars.scrape()
    mars.update({}, mars_data, upsert=True)
    #Redirect to the homepage
    return redirect("/", code=302)

if __name__ == "__main__":
    app.run(debug=True)


import numpy as np
from scipy.optimize import minimize
import scipy.io

def sigmoid(z):
    return 1.0/(1 +  np.e**(-z))

def lrCostFunction(theta,X,y,reg_param):
    m = len(y)
    J =((np.sum(-y*np.log(sigmoid(np.dot(X,theta)))-
       (1-y)*(np.log(1-sigmoid(np.dot(X,theta))))))/m +
       (reg_param/m)*np.sum(theta**2))

    grad_0 = (np.sum((sigmoid(np.dot(X,theta))-y)[:,None]*X,axis=0)/m)
    grad_reg = grad_0 + (reg_param/m)*theta
    grad_reg[0] = grad_0[0]
    return (J,grad_reg)

def oneVsAll(X, y, num_labels, reg_param):
    n = np.size(X,1)
    theta = np.zeros((n,num_labels))
    def findOptParam(p_num):
        outcome = np.array(y == p_num).astype(int)
        initial_theta = theta[:,p_num]
        results = minimize(lrCostFunction,
			   initial_theta,
                           method='Newton-CG',
                           args=(X,outcome,reg_param),
                           jac=True,
		           tol=1e-6,
                           options={'maxiter':400,
                                    'disp':True})
        theta[:,p_num] = results.x

    for digit in range(10):
        findOptParam(digit)

    return theta

def predictOneVsAllAccuracy(est_theta,X):

    probs = np.dot(X,est_theta)
    predict = np.argmax(probs,axis=1)

    return predict

def predict(theta1,theta2,X):
    m = len(X)
    if np.ndim(X) == 1:
        X = X.reshape((-1,1))
    D1 = np.hstack((np.ones((m,1)),X))

    hidden_pred = np.dot(D1,theta1.T)
    ones = np.ones((len(hidden_pred),1))
    hidden_pred = sigmoid(hidden_pred)
    hidden_pred = np.hstack((ones,hidden_pred))
    output_pred = np.dot(hidden_pred,theta2.T)
    output_pred = sigmoid(output_pred)
    p = np.argmax(output_pred,axis=1)

    return p

input_layer_size = 400
num_labels = 10

raw_mat = scipy.io.loadmat("ex3data1.mat")
X = raw_mat.get("X")
y = raw_mat.get("y").flatten()
y[y== 10] = 0

m = np.hstack((np.ones((len(y),1)),X))# add column of ones

rand_indices = np.random.randint(0,len(m),100)
sel = X[rand_indices,:]

reg_param = 1.0
theta = oneVsAll(m,y,10,reg_param)

predictions = predictOneVsAllAccuracy(theta,m)
accuracy = np.mean(y == predictions) * 100
print(accuracy)


import dash
from dash import dcc
from dash import html
import dash_daq as daq
from dash.dependencies import Input, Output

import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly.express as px
import umap
from umap import UMAP

import dash_bootstrap_components as dbc

# Launch the application
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

# Step 2. Import the dataset
#df = pd.read_csv('finance-charts-apple.csv')

with open('/mnt/c/Users/Ebru-as-user/Downloads/Leukemia_GSE9476.csv', 'r') as f:
  df = pd.read_csv(f)
# saving the string version of the type column to use for labelling
df_type_copy = df['type']

df['type'] = pd.factorize(df['type'])[0] + 1

# UMAP projection of data
reducer = UMAP(n_neighbors=3, min_dist=0.6, n_components=3,
               init='random', random_state=0)
embedding = reducer.fit_transform(df)

# Labels for axes of each plot
x_col = 'UMAP X'
y_col = 'UMAP Y'
z_col = 'UMAP Z'

x_col2 = 'FLT3'
y_col2 = 'NPM1'
z_col2 = 'IDH1'

# 3D arrays for the first and second plot
plot1_axes = embedding

plot2_axes = np.array(
    df[['206674_at', '221923_s_at', '201193_at']].values.tolist())

#boxes = ['214983_at', '206082_at', '210794_s_at', '203591_s_at']

# default columns to use for the box-and-whisker plot if the user doesn't select anything
boxes = ['205780_at', '211725_s_at', '208478_s_at', '203728_at']

# storing the max and mins of each dataset for later use
max_x1 = max(plot1_axes[:, 0])
min_x1 = min(plot1_axes[:, 0])

max_y1 = max(plot1_axes[:, 1])
min_y1 = min(plot1_axes[:, 1])

max_z1 = max(plot1_axes[:, 2])
min_z1 = min(plot1_axes[:, 2])

max_x2 = max(plot2_axes[:, 0])
min_x2 = min(plot2_axes[:, 0])

max_y2 = max(plot2_axes[:, 1])
min_y2 = min(plot2_axes[:, 1])

max_z2 = max(plot2_axes[:, 2])
min_z2 = min(plot2_axes[:, 2])

box_plots = go.Figure()
#for col in boxes:
#  box_plots.add_trace(go.Box(y=df[col], name=col))

#box_plots.add_trace(go.Box(y=df['petal_width']))
#box_plots.add_trace(go.Box(y=df['petal_length']))

# Creating the figures: each have one selection cube and whatever the plot will be
fig = go.Figure()

fig.add_trace(go.Mesh3d(name="cube",
                        # 8 vertices of a cube
                        x=[0, 0, 1, 1, 0, 0, 1, 1],
                        y=[0, 1, 1, 0, 0, 1, 1, 0],
                        z=[0, 0, 0, 0, 1, 1, 1, 1],
                        # i, j and k give the vertices of triangles
                        i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
                        j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
                        k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], opacity=0.20
                        ))

fig2 = go.Figure()

fig2.add_trace(go.Mesh3d(name="cube",
                        # 8 vertices of a cube
                         x=[0 + min_x2, 0 + min_x2, 1 + min_x2, 1 + min_x2,
                            0 + min_x2, 0 + min_x2, 1 + min_x2, 1 + min_x2],
                         y=[0 + min_y2, 1 + min_y2, 1 + min_y2, 0 +
                            min_y2, 0 + min_y2, 1 + min_y2, 1 + min_y2, 0 + min_y2],
                         z=[0 + min_z2, 0 + min_z2, 0 + min_z2, 0 + min_z2, 1 +
                            min_z2, 1 + min_z2, 1 + min_z2, 1 + min_z2],
                        # i, j and k give the vertices of triangles
                        i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
                        j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
                        k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], opacity=0.20
                        ))

#fig.add_trace(go.Scatter3d(
#    name="Bone_Marrow_CD34", x=embedding[:, 0][0:8], y=embedding[:, 1][0:8], z=embedding[:, 2][0:8]))

#fig.add_trace(go.Scatter3d(
#    name="Bone_Marrow", x=embedding[:, 0][9:18], y=embedding[:, 1][9:18], z=embedding[:, 2][9:18]))

#fig.add_trace(go.Scatter3d(
#    name="AML", x=embedding[:, 0][19:44], y=embedding[:, 1][19:44], z=embedding[:, 2][19:44]))

#fig.add_trace(go.Scatter3d(
#    name="PB", x=embedding[:, 0][45:53], y=embedding[:, 1][45:53], z=embedding[:, 2][45:53]))

#fig.add_trace(go.Scatter3d(
#    name="PBSC_CD34", x=embedding[:, 0][54:63], y=embedding[:, 1][54:63], z=embedding[:, 2][54:63]))

fig.add_trace(go.Scatter3d(
    name="selected", x=plot1_axes[:, 0], y=plot1_axes[:, 1], z=plot1_axes[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}", marker=dict(opacity=1, color=df['type'])))

fig.add_trace(go.Scatter3d(
    name="unselected", x=plot1_axes[:, 0], y=plot1_axes[:, 1], z=plot1_axes[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}", marker=dict(opacity=0.5, color=df['type'])))

#fig2.add_trace(go.Scatter3d(
#    name="unselected", x=embedding[:, 0], y=embedding[:, 1], z=embedding[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}", marker=dict(opacity=0.5, color=df['type'])))

#fig2.add_trace(go.Scatter3d(
#    name="selected", x=embedding[:, 0], y=embedding[:, 1], z=embedding[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}", marker=dict(opacity=1, color=df['type'])))

fig2.add_trace(go.Scatter3d(
    name="selected", x=plot2_axes[:, 0], y=plot2_axes[:, 1], z=plot2_axes[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}",  marker=dict(opacity=1, color=df['type'])))

fig2.add_trace(go.Scatter3d(
    name="unselected", x=plot2_axes[:, 0], y=plot2_axes[:, 1], z=plot2_axes[:, 2], customdata=df_type_copy, hovertemplate="Type: %{customdata}",  marker=dict(opacity=0.5, color=df['type'])))

fig.update_layout(showlegend = True)

#fig.update_xaxes(range=[1.5, 4.5])
#fig.update_yaxes(range=[3, 9])
#fig.update_yaxes(range=[3, 9])

# Organizing the app layout
app.layout = html.Div([dbc.Row([html.H1("Dash for 3D Data Exploration", style={'textAlign': 'center', 'color': '#7FDBFF'}),
                                html.H4(f'Select Variable for Propagation', style={
                                        'color': '#7FDBFF'}),
                                dcc.Dropdown(list(df.columns),
                                             id="box_dropdown", multi=True),
                                html.H5("Note: Hover over the points to see their color-coded classifications")]),
                       html.Br(),
                       dbc.Row([
                            dbc.Col([
                                dbc.Row(
                                    html.H2("UMAP Projection of Leukemia gene expression")),
                                html.Br(),
                                dbc.Row(html.Div(children=[html.H4('Select on first graph:', style={
                                        'color': '#7FDBFF', 'display': 'inline-block'}), daq.BooleanSwitch(id='include1', on=True, style={'display': 'inline-block'})])),
                                html.H4('Exploration Box Size:',
                                        style={'color': '#7FDBFF'}),
                                dcc.Slider(1, 15, value=4, marks=None, id='size1',
                                           tooltip={"placement": "bottom", "always_visible": True}),
                                dbc.Row(dcc.Graph(id='plot1', figure=fig)),
                                dbc.Row([
                                    dbc.Col([html.H4(f'X axis: {x_col}', style={'color': '#7FDBFF'}),
                                             dcc.Slider(min_x1, max_x1, marks=None, value=0, id='xslider1',
                                        tooltip={"placement": "bottom", "always_visible": True})]),
                                    dbc.Col([html.H4(f'Y axis: {y_col}', style={'color': '#7FDBFF'}),
                                            dcc.Slider(min_y1, max_y1, marks=None, value=0, id='yslider1',
                                                       tooltip={"placement": "bottom", "always_visible": True})]),
                                    dbc.Col([html.H4(f'Z axis: {z_col}', style={'color': '#7FDBFF'}),
                                            dcc.Slider(min_z1, max_z1, marks=None, value=0, id='zslider1',
                                                       tooltip={"placement": "bottom", "always_visible": True})])
                                ])], style={'border': '3px solid black'}
                            ),
                            dbc.Col([
                                dbc.Row(
                                    html.H2("Expression of top markers according to article below")),
                                html.A(
                                    "Link to Paper", href="https://arupconsult.com/ati/acute-myeloid-leukemia-molecular-genetic-testing"),
                                html.Br(),
                                dbc.Row(html.Div(children=[html.H4('Select on second graph:', style={
                                        'color': '#7FDBFF', 'display': 'inline-block'}), daq.BooleanSwitch(id='include2', on=True, style={'display': 'inline-block'})])),
                                html.H4('Exploration Box Size:',
                                        style={'color': '#7FDBFF'}),
                                dcc.Slider(1, 15, marks=None, value=0, id='size2',
                                           tooltip={"placement": "bottom", "always_visible": True}),
                                dbc.Row(dcc.Graph(id='plot2', figure=fig2)),
                                dbc.Row([
                                    dbc.Col([
                                        html.H4(f'X axis: {x_col2}', style={
                                                'color': '#7FDBFF'}),
                                        dcc.Slider(min_x2, max_x2, marks=None, value=min_x2, id='xslider2',
                                            tooltip={"placement": "bottom", "always_visible": True})
                                    ]),
                                    dbc.Col([html.H4(f'Y axis: {y_col2}', style={'color': '#7FDBFF'}),
                                             dcc.Slider(min_y2, max_y2, marks=None, value=min_y2, id='yslider2',
                                                        tooltip={"placement": "bottom", "always_visible": True})
                                    ]),
                                    dbc.Col([html.H4(f'Z axis: {z_col2}', style={'color': '#7FDBFF'}),
                                             dcc.Slider(min_z2, max_z2, marks=None, value=min_z2, id='zslider2',
                                                        tooltip={"placement": "bottom", "always_visible": True})
                                    ])
                                ])], style={'border': '3px solid black'}
                            ),
                        dbc.Col(dcc.Graph(id='box', figure=box_plots))]
)])

# Step 4. Create a Dash layout

#list(df.columns)

# Step 5. Add callback functions

@app.callback(Output('plot1', 'figure'),
              [Input('xslider1', 'value'),
              Input('yslider1', 'value'),
              Input('zslider1', 'value'),
              Input('size1', 'value'),
              Input('include1', 'on')])
def update_figure1(X, Y, Z, size, on):

    # redraw the cube to the new coordinates

    if on == True:
        newX = [0 + X, 0 + X, 1 + X + size, 1 + X +
                size, 0 + X, 0 + X, 1 + X + size, 1 + X + size]
        newY = [0 + Y, 1 + Y + size, 1 + Y + size, 0 +
                Y, 0 + Y, 1 + Y + size, 1 + Y + size, 0 + Y]
        newZ = [0 + Z, 0 + Z, 0 + Z, 0 + Z, 1 + Z +
                size, 1 + Z + size, 1 + Z + size, 1 + Z + size]
        fig.update_traces(x=newX, y=newY, z=newZ, i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
                        j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
                        k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], opacity = 0.2, selector=dict(name="cube"))
        #fig.update_xaxes(range=[1.5, 4.5])
        #fig.update_yaxes(range=[3, 9])
        #fig.update_yaxes(range=[3, 9])

        fig.update_xaxes(range=[min_x1, max_x1])
        fig.update_yaxes(range=[min_y1, max_y1])
        fig.update_yaxes(range=[min_z1, max_z1])

        # create a new dataframe that contains the filtered points (the points that the exploration box overlaps)
        em_df = pd.DataFrame(plot1_axes, columns=['0', '1', '2'])
        em_filtered = em_df[(((em_df['0'] >= X) & (em_df['0'] <= X+size))
                            & ((em_df['1'] >= Y) & (em_df['1'] <= Y+size))
                            & ((em_df['2'] >= Z) & (em_df['2'] <= Z+size)))].index.to_list()
        df_filtered = em_df.filter(items=em_filtered, axis=0)

        # If points have been selected, make those selected points 100% opacity, and the unselected points 50% opacity
        if not df_filtered.empty:
            fig.update_traces(x=df_filtered.iloc[:, 0], y=df_filtered.iloc[:, 1], z=df_filtered.iloc[:, 2], marker=dict(
                opacity=1), selector=dict(name="selected"))
        else:
            fig.update_traces(marker=dict(opacity=0.5), selector=dict(name="selected"))
    # If the user doesn't want to select, then hide the exploration box, and make all the points look unselected
    else:
        fig.update_traces(marker=dict(
            opacity=0.5), selector=dict(name="selected"))
        fig.update_traces(opacity=0, selector=dict(name="cube"))

    return fig

# same as the above callback, but to update the second figure
@app.callback(Output('plot2', 'figure'),
              [Input('xslider2', 'value'),
              Input('yslider2', 'value'),
              Input('zslider2', 'value'),
              Input('size2', 'value'),
              Input('include2', 'on')])
def update_figure2(X, Y, Z, size, on):

    if on == True:
        # redraw the cube to the new coordinates

        newX = [0 + X, 0 + X, 1 + X + size, 1 + X +
                size, 0 + X, 0 + X, 1 + X + size, 1 + X + size]
        newY = [0 + Y, 1 + Y + size, 1 + Y + size, 0 +
                Y, 0 + Y, 1 + Y + size, 1 + Y + size, 0 + Y]
        newZ = [0 + Z, 0 + Z, 0 + Z, 0 + Z, 1 + Z +
                size, 1 + Z + size, 1 + Z + size, 1 + Z + size]

        fig2.update_traces(x=newX, y=newY, z=newZ, i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
                        j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
                        k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], opacity = 0.2, selector=dict(name="cube"))

        fig2.update_xaxes(range=[min_x2, max_x2])
        fig2.update_yaxes(range=[min_y2, max_y2])
        fig2.update_yaxes(range=[min_z2, max_z2])

        em_df = pd.DataFrame(plot2_axes, columns=['0', '1', '2'])
        em_filtered = em_df[(((em_df['0'] >= X) & (em_df['0'] <= X+size))
                            & ((em_df['1'] >= Y) & (em_df['1'] <= Y+size))
                            & ((em_df['2'] >= Z) & (em_df['2'] <= Z+size)))].index.to_list()
        df_filtered = em_df.filter(items=em_filtered, axis=0)
        if not df_filtered.empty:
            fig2.update_traces(x=df_filtered.iloc[:, 0], y=df_filtered.iloc[:, 1], z=df_filtered.iloc[:, 2], marker=dict(
                opacity=1), selector=dict(name="selected"))
        else:
            fig2.update_traces(marker=dict(opacity=0.5), selector=dict(name="selected"))
    else:
        fig2.update_traces(marker=dict(
            opacity=0.5), selector=dict(name="selected"))
        fig2.update_traces(opacity=0, selector=dict(name="cube"))

    return fig2
#df_filtered = df['petal_length'].between(
    #    X-1, X, inclusive=True)

    # add or delete any boxes based on the dropdown selections
    # filter the dataframe based on the selection
    #df_filtered = df[(((df[x_col] >= X) & (df[x_col] <= X+size+1))
    #                  & ((df[y_col] >= Y) & (df[y_col] <= Y+size+1))
    #                  & ((df[z_col] >= Z) & (df[z_col] <= Z+size+1)))]
    # make sure this applies to all box plot traces in the figure

# Callback to update the box-and-whisker plot with what has been selected
@app.callback(Output('box', 'figure'), [Input('xslider1', 'value'),
              Input('yslider1', 'value'),
              Input('zslider1', 'value'),
              Input('xslider2', 'value'),
              Input('yslider2', 'value'),
              Input('zslider2', 'value'),
              Input('size1', 'value'),
              Input('size2', 'value'),
              Input('include1', 'on'),
              Input('include2', 'on'),
              Input('box_dropdown', 'value')])
def update_box(X1, Y1, Z1, X2, Y2, Z2, size1, size2, on1, on2, values):
    em_df = pd.DataFrame(plot1_axes, columns=['0', '1', '2'])
    em_df2 = pd.DataFrame(plot2_axes, columns=['0', '1', '2'])
    if on1 == True:
        em_filtered1 = em_df[(((em_df['0'] >= X1) & (em_df['0'] <= X1+size1))
                    & ((em_df['1'] >= Y1) & (em_df['1'] <= Y1+size1))
                    & ((em_df['2'] >= Z1) & (em_df['2'] <= Z1+size1)))].index.to_list()
    else:
        em_filtered1 = []
    if on2 == True:
        em_filtered2 = em_df2[(((em_df2['0'] >= X2) & (em_df2['0'] <= X2+size2))
                            & ((em_df2['1'] >= Y2) & (em_df2['1'] <= Y2+size2))
                            & ((em_df2['2'] >= Z2) & (em_df2['2'] <= Z2+size2)))].index.to_list()
    if (on1 == True) and (on2==True):
        em_filtered = np.intersect1d(em_filtered1, em_filtered2)
    elif (on1==True) and (on2 == False):
        em_filtered = em_filtered1
    else:
        em_filtered = em_filtered2
    df_filtered = df.filter(items=em_filtered, axis=0)
    current_boxes = []
    for part in box_plots.data:
        if part.name is not None: current_boxes.append(part.name)
    if values is not None:
        copy_boxes = values
    else:
        copy_boxes = boxes
    for col in copy_boxes:
        if(col not in current_boxes):
            box_plots.add_trace(go.Box(y=df_filtered[col], name=col))
        else:
            box_plots.update_traces(
                y=df_filtered[col], selector=dict(name=col))
    return box_plots

def generate_box():
    return

# Step 6. Add the server clause
if __name__ == '__main__':
    app.run_server()


import torch
from torchvision import datasets, transforms

# Define paths for the data
data_dir = 'flowers'
train_dir = data_dir + '/train'
valid_dir = data_dir + '/valid'
test_dir = data_dir + '/test'

dirs = {
    'train': train_dir,
    'val': valid_dir,
    'test': test_dir
}

# Define transforms for the training, validation, and testing sets
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomRotation(30),
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(255),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'test': transforms.Compose([
        transforms.Resize(255),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])
}

# Load the datasets with ImageFolder
image_datasets = {
    x: datasets.ImageFolder(dirs[x], transform=data_transforms[x])
    for x in ['train', 'val', 'test']
}

# Using the image datasets and the transforms, define the dataloaders
dataloaders = {
    x: torch.utils.data.DataLoader(image_datasets[x], batch_size=64, shuffle=True)
    for x in ['train', 'val', 'test']
}


from base64 import decodebytes
import discord
from discord import embeds
from discord.ext import commands
import random
import datetime

from requests.models import Response

class Events(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_ready(self):
        print("Events Cog has been loaded....\n")

    @commands.Cog.listener()
    async def on_member_join(self, member):
        channel = self.bot.get_channel(585411891447463956)

        response = [
            f"Hopefully you wont regret joining {member.name}",
            f"this is pretty much a really dead ass server but welcome {member.name}",
            f"Enjoy the stay {member.name}",
            f"This isnt a server for you if you easily can get offended, but welcome {member.name}",
            f"I am not the admin bot, im just very based, hope you enjoy the stay {member.name}",
            f"Retarded server but ok, have some fun {member.name}",
            f"Oh i didnt notice you there, {member.name}, JK i did, dw im not your dad",
        ]

        embed = discord.Embed(description=(random.choice(response)), colour=0xBF8040)
        embed.set_thumbnail(url=member.avatar_url)
        embed.set_author(name=member.name, icon_url=member.avatar_url)
        embed.set_footer(text=member.guild, icon_url=member.guild.icon_url)
        embed.timestamp = datetime.datetime.utcnow()
        await channel.send(embed=embed)

    @commands.Cog.listener()
    async def on_member_remove(self, member):

        channel = self.bot.get_channel(585411891447463956)

        response = [
            f"lol, pussy {member.name}",
            f"no one really wanted you to stay here anyway {member.name}",
            f"got offended and left to cry?, {member.name}",
            f"aw you didnt get personal suck jobs from saam? lgbtq+ ass",
            f"some corny dude aka, {member.name} left",
            f"{member.name} was a pain in the asshole anyway",
        ]
        embed = discord.Embed(
            description=(random.choice(response)),
            colour=0xBF8040,
        )
        embed.set_thumbnail(url=member.avatar_url)
        embed.set_author(name=member.name, icon_url=member.avatar_url)
        embed.set_footer(text=member.guild, icon_url=member.guild.icon_url)
        embed.timestamp = datetime.datetime.utcnow()
        await channel.send(embed=embed)

    @commands.Cog.listener()
    async def on_command_error(self, ctx, error):
        ignored = (commands.CommandNotFound, commands.UserInputError)
        if isinstance(error, ignored):
            return

        if isinstance(error, commands.CommandOnCooldown):
            m, s = divmod(error.retry_after, 60)
            h, m = divmod(m, 60)

            if int(h) == 0 and int(m) == 0:
                await ctx.send(
                    f"```you must wait {int(s)} seconds to use this command!```"
                )
            elif int(h) == 0 and int(m) != 0:
                await ctx.send(
                    f"```you must wait {int(m)} minutes, {int(s)} seconds to use this command!```"
                )
            else:
                await ctx.send(
                    f"```you must wait {int(h)}hours, {int(m)} minutes, {int(s)} seconds to use this command!```"
                )
        elif isinstance(error, commands.CheckAnyFailure):
            await ctx.send(
                "```I don't understand what you mean, can you refer to the help command```"
            )
        raise error

def setup(bot):
    bot.add_cog(Events(bot))


from classifiers.NCC import NCC
from classifiers.NBC import NBC
from classifiers.GNB import GNB

from sklearn.naive_bayes import GaussianNB

from sklearn import metrics
from sklearn import datasets

import MNIST

import numpy as np

def modify_data(data):
    modified = []
    for d in data:
        tmp = []
        for value in d:
            if value < 5:
                tmp.append(0)
            elif value < 10:
                tmp.append(1)
            else:
                tmp.append(2)
        modified.append(np.array(tmp))
    return np.array(modified)

def modify_target(target):
    modified = []
    for t in target:
        if t < 3:
            modified.append(0)
        elif t < 6:
            modified.append(1)
        else:
            modified.append(2)
    return np.array(modified)

def main():
    # SciKitLearn digits (2.1)
    digits = datasets.load_digits()

    split = int(0.7 * digits.data.shape[0])
    train_feature = digits.data[:split]
    train_label = digits.target[:split]
    test_feature = digits.data[split:]
    test_labels = digits.target[split:]

    # SciKitLearn digits summarised (2.2)
    modified_digits_data = modify_data(digits.data)
    modified_digits_labels = digits.target

    train_feature_mod = modified_digits_data[:split]
    train_label_mod = modified_digits_labels[:split]
    test_feature_mod = modified_digits_data[split:]
    test_label_mod = modified_digits_labels[split:]

    # MNIST_Light (2.3)
    mnist = MNIST.MNISTData('MNIST_Light/*/*.png')
    train_features_mnist, test_features_mnist, train_labels_mnist, test_labels_mnist = mnist.get_data()

    # gnb = GNB()
    # gnb.fit(train_feature, train_label)
    # y_pred = gnb.predict(test_feature)
    # gnb = GaussianNB()
    # gnb.fit(train_feature, train_label)
    # y_pred = gnb.predict(test_feature)
#
    # print("Classification report SKLearn GNB:\n%s\n"
    #   % (metrics.classification_report(test_labels, y_pred)))
    # print("Confusion matrix SKLearn GNB:\n%s" % metrics.confusion_matrix(test_labels, y_pred))

    ncc = NCC()
    ncc.fit(train_feature, train_label)
    y_pred = ncc.predict(test_feature)

    print("Classification report NCC (dataset 2.1):\n%s\n"
      % (metrics.classification_report(test_labels, y_pred)))
    print("Confusion matrix NCC:\n%s" % metrics.confusion_matrix(test_labels, y_pred))

    ncc2 = NCC()
    ncc2.fit(train_feature_mod, train_label_mod)
    y_pred_mod = ncc2.predict(test_feature_mod)

    print("Classification report NCC (dataset 2.2):\n%s\n"
      % (metrics.classification_report(test_label_mod, y_pred_mod)))
    print("Confusion matrix NCC:\n%s" % metrics.confusion_matrix(test_label_mod, y_pred_mod))

    ncc3 = NCC()
    ncc3.fit(train_features_mnist, train_labels_mnist)
    y_pred_mnist = ncc3.predict(test_features_mnist)

    print("Classification report NCC (dataset 2.3):\n%s\n"
      % (metrics.classification_report(test_labels_mnist, y_pred_mnist)))
    print("Confusion matrix NCC:\n%s" % metrics.confusion_matrix(test_labels_mnist, y_pred_mnist))

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# coding: utf-8

import numpy as np
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
import os
from os import path
import re

class WeatherMax():
    '''
    pass file directory path with forward slashes
    '''
    def __init__(self,directorypath):
        self.directorypath = directorypath
        self.df = None
        #self.weather_result
        #self.date
        #self.time
        #self.region

    def csvtodataset(self):
        os.chdir(self.directorypath)

        #read csv files in directory

    def patable(self):
        for file in os.listdir():
            if file.endswith(".csv"):
                file1 = file
                df = pd.read_csv(os.path.abspath(file1))

                #select required columns and enrich data with partition attributes

                df = df[['ForecastSiteCode','ObservationTime','ObservationDate','ScreenTemperature','SiteName','Region']]
                df = df.sort_values(by=['ForecastSiteCode','ObservationDate','ObservationTime'])
                df = df.reset_index(drop=True)
                df['ObsYear'] = pd.DatetimeIndex(df['ObservationDate']).year
                df['ObsMonth'] = pd.DatetimeIndex(df['ObservationDate']).month
                df['ObsDay'] = pd.DatetimeIndex(df['ObservationDate']).day

                table = pa.Table.from_pandas(df)

                #create additional files for testing

                file1 = file1.replace(".csv",".")
                file2 = file1 + 'parquet.snappy'
                pq.write_table(table, file2,compression='snappy')

                pq.write_to_dataset(table,root_path='weather_results',partition_cols=['ObsYear','ObsMonth','Region'])

    #create folder schema
    def builddataset(self):
        self.patable()

    def weathertable(self):
        weather_data = pq.ParquetDataset('weather_results/')
        table = weather_data.read()
        weather_table_df = table.to_pandas()
        return weather_table_df

    def weathermax_row(self):
        weather_table_df = self.weathertable()
        weather_result = weather_table_df.loc[weather_table_df['ScreenTemperature'].idxmax()]
        return weather_result

     #return max temp date
    def weather_date(self):
        weather_result = self.weathermax_row()
        date = weather_result['ObservationDate'][:9]
        return date

    #return max temp
    def weather_temp(self):
        weather_result = self.weathermax_row()
        temp = weather_result['ScreenTemperature']
        return temp

    #return max temp region
    def weather_region(self):
        weather_result = self.weathermax_row()
        region = weather_result['Region']
        return region

    #print questions and answers
    def prntresult(self):
        a = "Which date was the hottest day? " + str(self.weather_date()) +'\n'
        b = "What was the (max) temperature on that day? " + str(self.weather_temp()) +'\n'
        c = "In which region was the hottest day? " + str(self.weather_region())

        result = print(a,b,c)
        return result


import cv2
import numpy as np
from PIL import Image

def main():
    capture = cv2.VideoCapture(0)

    while True:
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        ret, frame = capture.read()
        cv2.imshow('Current', frame)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        image = Image.fromarray(gray)

        qrDetector=cv2.QRCodeDetector()
        retval , points ,straight_qrcode = qrDetector.detectAndDecode(frame)
        if len(retval)>0:
            print(retval)
            straight_qrcode = np.uint8(straight_qrcode)
            cv2.imshow('rectified qr code',straight_qrcode)

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


import time
#import img2txt
import os
import json
from PIL import Image

def load_file(fpath):  # fpath是具体的文件 ，作用：#str to list
    assert os.path.exists(fpath)  # assert() raise-if-not
    with open(fpath, 'r') as fid:
        lines = fid.readlines()
    records = [json.loads(line.strip('\n')) for line in lines]  # str to list
    return records

def img2txt(odgtpath, respath):
    records = load_file(odgtpath)  # 提取odgt文件数据
    record_list = len(records)  # 获得record的长度，循环遍历所有数据。
    print(os.getcwd())
    # os.mkdir(os.getcwd() + respath)
    with open(respath, 'w') as txt:
        for i in range(record_list):
            file_name = records[i]['ID'] + '.jpg'
            file_name = str("/Image/" + file_name)
            txt.write(file_name + '\n')

def tonormlabel(odgtpath, storepath):
    records = load_file(odgtpath)           #records = img2txt.load_file(odgtpath)
    record_list = len(records)
    print(record_list)
    categories = {}
    # txt = open(respath, 'w')
    for i in range(record_list):
        txt_name = storepath + records[i]['ID'] + '.txt'
        file_name = records[i]['ID'] + '.jpg'
        #print(i)
        im = Image.open("./Image/" + file_name)
        height = im.size[1]
        width = im.size[0]
        file = open(txt_name, 'w')
        gt_box = records[i]['gtboxes']
        gt_box_len = len(gt_box)  # 每一个字典gtboxes里，也有好几个记录，分别提取记录。
        for j in range(gt_box_len):
            category = gt_box[j]['tag']
            if category not in categories:  # 该类型不在categories，就添加上去
                new_id = len(categories) + 1  # ID递增
                categories[category] = new_id
            category_id = categories[category]  # 重新获取它的类别ID
            fbox = gt_box[j]['fbox']  # 获得全身框
#            norm_x = fbox[0] / width
#            norm_y = fbox[1] / height
            norm_w = fbox[2] / width
            norm_h = fbox[3] / height
            norm_x = fbox[0] / width + 0.5 * norm_w
            norm_y = fbox[1] / height + 0.5 * norm_h

            '''
            norm_x = 0 if norm_x <= 0 else norm_x
            norm_x = 1 if norm_x >= 1 else norm_x
            norm_y = 0 if norm_y <= 0 else norm_y
            norm_y = 1 if norm_y >= 1 else norm_y
            norm_w = 0 if norm_w <= 0 else norm_w
            norm_w = 1 if norm_w >= 1 else norm_w
            norm_h = 0 if norm_h <= 0 else norm_h
            norm_h = 1 if norm_h >= 1 else norm_h
            '''
            blank = ' '
            if j == gt_box_len-1:
                file.write(str(category_id - 1) + blank + '{:.6f}'.format(norm_x) + blank + '{:.6f}'.format(norm_y) + blank
                           + '{:.6f}'.format(norm_w) + blank + '{:.6f}'.format(norm_h))
            else:
                file.write(str(category_id - 1) + blank + '{:.6f}'.format(norm_x) + blank + '{:.6f}'.format(norm_y) + blank
                           + '{:.6f}'.format(norm_w) + blank + '{:.6f}'.format(norm_h) + '\n')

if __name__ == '__main__':
    odgtpath = "./annotation_val.odgt"           #"/datasets/crowdhuman/annotation_train.odgt"
    respath = "./annotation_name.txt"  #"/datasets/crowdhuman/train_name.txt"
    storepath = "./annotation/"                    #"/datasets/crowdhuman/labels/train_all/Image/"
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))  # 格式化输出时间
    start = time.time()
    tonormlabel(odgtpath, storepath)
    end = time.time()
    print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    print('已完成轉換，共耗時{:.5f}s'.format(end - start))


from fastapi import APIRouter
from BusinessLayer.PersonaNatural import *
from EntityLayer.PersonaNaturalEntity import *
from fastapi.encoders import jsonable_encoder
from Utilidades.Entidades.ResponseAPI import ResponseAPI, ResponseAPIError

PersonaNaturalRouter = APIRouter()
ApiName = "PersonaNatural"

@PersonaNaturalRouter.post(f"/api/{ApiName}/Save", tags=[ApiName])
def Save(Ent: PersonaNaturalSaveModel):
    try:
        Ent = PersonaNatural.Save(Ent)
        return jsonable_encoder(ResponseAPI.Response(Ent))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())

@PersonaNaturalRouter.get(f"/api/{ApiName}/GetItems/", tags=[ApiName])
def GetItems():
    try:
        jsonData = PersonaNatural.GetItems()
        return jsonable_encoder(ResponseAPI.Response(jsonData))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())

@PersonaNaturalRouter.get(f"/api/{ApiName}/GetItem/{{Id}}/", tags=[ApiName])
def GetItem(Id: int):
    try:
        jsonData = PersonaNatural.GetItem(Id)
        return jsonable_encoder(ResponseAPI.Response(jsonData))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())

@PersonaNaturalRouter.delete(f"/api/{ApiName}/Delete/{{Id}}", tags=[ApiName])
def Delete(Id: int):
    try:
        jsonData = PersonaNatural.Delete(Id)
        return jsonable_encoder(ResponseAPI.Response(jsonData))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())

@PersonaNaturalRouter.get(f"/api/{ApiName}/GetMainItems", tags=[ApiName])
def GetMainItems():
    try:
        jsonData = PersonaNatural.GetMainItems()
        return jsonable_encoder(ResponseAPI.Response(jsonData))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())

@PersonaNaturalRouter.get(f"/api/{ApiName}/GetCabeceraItem/{{Id}}/", tags=[ApiName])
def GetCabeceraItem(Id: int):
    try:
        jsonData = PersonaNatural.GetCabeceraItem(Id)
        return jsonable_encoder(ResponseAPI.Response(jsonData))
    except Exception as e:
        print(e)
        return jsonable_encoder(ResponseAPIError.Error())


from . import views
from django.urls import path

urlpatterns = [
    path('admin_dashboard', views.admin_dashboard, name="admin_dashboard"),
    path('admin_packages', views.admin_packages, name="admin_packages"),
    path('update_package/<package_id>', views.update_package, name="update_package"),
    path('delete_package/<package_id>', views.delete_package, name="delete_package"),

]


from tkinter import Frame, DoubleVar
from tkinter.ttk import Scale

from typing import Dict, Tuple, List

from ui.misc import NoneTypeCheck
from ui.Components import Component

class Range(Component):
    """
    Tkinter range value
    """
    def __init__(self, parent: Frame, style: Dict, geometry: Tuple[int] | List[int]):
        super().__init__(parent, style, geometry)
        self.start = NoneTypeCheck(style.get("start"), 0)
        self.end = NoneTypeCheck(style.get("end"), 10)
        self.defaultValue = NoneTypeCheck(style.get("default"), 1)
        self.value = DoubleVar()
        self.fetchData = self.get
        self.setComponent()

    def setComponent(self):
        self.component = Scale(self.componentFrame,
                               from_=self.start,
                               to=self.end,
                               variable=self.value,
                               value=self.defaultValue)

    def get(self):
        return self.value.get()


#!/usr/bin/env python3

"""
    1 Aug 2022 Taeho Choi created for longhorn API python client
    KUBECONFIG needs to be imported properly before running this script
"""

import time
import longhorn
import os
import json

#Warning msg to user
print("#"*40)
print("!! WARNING: This script can cause catastrophic consequences to your infrastructure !! ")
print("!! Please make sure you understand what you are trying to achieve clearly !! ")
print("#"*40)

print("Please make sure you have imported k8s config file correctly")
time.sleep(1)

print("Running kube proxy to redirect svc port to local")
os.system("kubectl port-forward services/longhorn-frontend 8080:http -n longhorn-system & ")
time.sleep(3)

#not using proxy since it will be internal network
os.system("export http_proxy= ; export https_proxy= ")

# If automation/scripting tool is inside the same cluster in which Longhorn is installed
longhorn_url = 'http://longhorn-frontend.longhorn-system/v1'
# If forwarding `longhorn-frontend` service to localhost
longhorn_url = 'http://localhost:8080/v1'

#Check to see if port is listening
os.system("curl http://localhost:8080/v1")

#Create longhorn client object with given URL
client = longhorn.Client(url=longhorn_url)

def print_menu():
    print("\n")
    for key in menu_options.keys():
        print (key, '--', menu_options[key] )
    print("\n")

#Volume Ops
def option1():
     print('Handle option \'Option 1\'')
     volumes = client.list_volume()
     vol_json = json.loads(json.dumps(volumes,default=vars))
     print("#"*200)
     print("These are the longhorn volumes")
     print("#"*200+"\n")
     for _ijson in vol_json["data"]:
        try:
            _pod_name = _ijson["kubernetesStatus"]['workloadsStatus'][0].get('podName')
        except TypeError:
            _pod_name = "N/A"
        print("ID:{} STATE:{} CONTROLLER:{:<15} SIZE:{:<4}GB NS:{:<15} POD_NAME:{:<15}".format(_ijson["id"], _ijson["state"], _ijson["replicas"][0].get("hostId"),int( _ijson["size"])/1024/1024/1024,_ijson["kubernetesStatus"].get("namespace"), _pod_name))

def option2():
     print('Handle option \'Option 2\'')
     vol_id = input("what is the volume name or id to check: ")
     output = client.by_id_volume(id=vol_id)
     print(json.dumps(output, indent=4, default=vars))

def option3():
     print('Handle option \'Option 3\'')
     vol_id = input("what is the volume name or id to attach: ")
     node_id = input("what is the node id to attach: ")
     testvol1 = client.by_id_volume(id=vol_id)
     output = testvol1.attach(hostId=node_id)
     print(json.dumps(output, indent=4, default=vars))

def option4():
     print('Handle option \'Option 4\'')
     vol_id = input("what is the volume name or id to detach: ")
     testvol1 = client.by_id_volume(id=vol_id)
     print(type(testvol1))
     print(testvol1)
     output = testvol1.detach()
     print(json.dumps(output, indent=4, default=vars))

def option5():
     print('Handle option \'Option 5\'')
     vol_id = input("what is the volume name or id for snapshot: ")
     snapshot = input("what is the snapshot name to create: ")
     vol_client = client.by_id_volume(id=vol_id)
     output = vol_client.snapshotCreate(name=snapshot)
     print(json.dumps(output, indent=4, default=vars))

def option6():
     print('Handle option \'Option 6\'')
     vol_id = input("what is the volume name or id for backup: ")
     snapshot_name = input("what is the snampshot name to backup: ")
     vol_client = client.by_id_volume(id=vol_id)
     output = vol_client.snapshotBackup(name=snapshot_name)
     print(json.dumps(output, indent=4, default=vars))

def option7():
     print('Handle option \'Option 7\'')
     vol_id = input("what is the volume name or id to update replica count: ")
     no_rep = int(input("what is the new no of replica count?: "))
     vol_client = client.by_id_volume(id=vol_id)
     output = vol_client.updateReplicaCount(replicaCount=no_rep)
     print(json.dumps(output, indent=4, default=vars))

#Node Ops
def option8():
     print('Handle option \'Option 8\'')
     volumes = client.list_node()
     vol_json = json.loads(json.dumps(volumes,default=vars))
     print("#"*40)
     print("These are the longhorn nodes")
     print("#"*40)
     for i in vol_json["data"]:
        print(i["id"])
     print("#"*40)

def option9():
     print('Handle option \'Option 9\'')
     node_id = input("what is the node id or name to check: ")
     output = client.by_id_node(id=node_id)
     print(json.dumps(output, indent=4, default=vars))

def option10():
     print('Handle option \'Option 10\'')
     node_id = input("what is the node id or name to disable: ")
     node1_obj = client.by_id_node(id=node_id)
     output = client.update(node1_obj, allowScheduling=False)
     print(json.dumps(output, indent=4, default=vars))

def option11():
     print('Handle option \'Option 11\'')
     node_id = input("what is the node id or name to enable: ")
     node1_obj = client.by_id_node(id=node_id)
     output = client.update(node1_obj, allowScheduling=True)
     print(json.dumps(output, indent=4, default=vars))

#Setting Ops
def option12():
     print('Handle option \'Option 12\'')
     settings = client.list_setting()
     settings_json = json.loads(json.dumps(settings,default=vars))
     print("#"*40)
     print("These are the longhorn cluster settings")
     print("#"*40)
     print(json.dumps(settings,indent=4,default=vars))

def option13():
     print('Handle option \'Option 13\'')
     setting_id = input("what is setting id or name to check: ")
     output = client.by_id_setting(id=setting_id)
     print(json.dumps(output, indent=4, default=vars))

def option14():
     print('Handle option \'Option 14\'')
     setting_id = input("what is the setting id or name to update: ")
     new_val = input("what is the new value for the setting: ")
     setting_obj = client.by_id_setting(id=setting_id)
     output = client.update(setting_obj, value=new_val)
     print(json.dumps(output, indent=4, default=vars))

def option15():
     print('Handle option \'Option 15\'')
     print('Thanks message before exiting')
     exit()

#Set dict for menu option and func mapping
menu_options = {
    #Volume operation
    1: 'List all volumes',
    2: 'Get volume by NAME/ID',
    3: 'Attach volume to node',
    4: 'Detach TESTVOL1',
    5: 'Create a snapshot of TESTVOL1 with NAME',
    6: 'Create a backup from a snapshot NAME',
    7: 'Update the number of replicas of TESTVOL1',
    #node operation
    8: 'List all nodes',
    9: 'Get node by NAME/ID',
    10: 'Disable scheduling for NODE1',
    11: 'Enable scheduling for NODE1',
    #Setting operation
    12: 'List all settings',
    13: 'Get setting by NAME/ID',
    14: 'Update a setting',
    15: 'Exit',
}

options = {
                1: option1,
                2: option2,
                3: option3,
                4: option4,
                5: option5,
                6: option6,
                7: option7,
                8: option8,
                9: option9,
                10: option10,
                11: option11,
                12: option12,
                13: option13,
                14: option14,
                15: option15,
        }

if __name__=='__main__':
    while(True):
        print_menu()
        option = ''
        try:
            option = int(input('Enter your choice: '))
        except:
            print('Wrong input. Please enter a number ...')
        #Check what choice was entered and act accordingly
        if option in options:
            options[option]()
        else:
            print('Invalid option. Please enter a number between 1 and 15.')