# importing the libraries required

from collections import Counter
from nltk.corpus.reader import sentiwordnet
import requests
import bs4
import string
import re
from nltk.tokenize import word_tokenize,sent_tokenize
from nltk.corpus import stopwords
from collections import Counter
from nltk.sentiment.vader import SentimentIntensityAnalyzer

# creating a method to parse and extract data from the url provided;
# Data cleaning, tokenization and emotion checking is added too.

def extract(url):

    # url = str(input("Please enter the url from where you want to extract the Information:\n"))

    headers = {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0',
    }

    r= requests.get(url, headers=headers)
    htmlcontent  = r.content

    # Parsing the html content using Beautiful Soup

    soup = bs4.BeautifulSoup(htmlcontent,"html.parser")

    article_title = soup.find("span",class_ = "td-bred-no-url-last").text
    article_body = soup.find("div", class_ = "td-post-content",).text

    directory = (r"")

    # get fileName from user
    filepath = directory + input("Enter filename: ")

    # Creates a new file
    with open(filepath, 'w', errors = "ignore") as f:
        f.write(article_title)
        f.write(article_body)

    with open(filepath,"r") as f:
        text = f.read()

    lower_case = text.lower()

    cleaned_text = lower_case.translate(str.maketrans("","",string.punctuation))

    tokenized_text = word_tokenize(cleaned_text,"english")

    final_text_list = []

    for word in tokenized_text:
        if word not in stopwords.words("english"):
            final_text_list.append(word)

    # print(final_text_list)

    emotion_list = []
    with open("emotions.txt","r") as f:
        for line in f:
            cleaned_emotions = line.replace("\n", "").replace("'","").replace(",","").strip()
            word,emotion = cleaned_emotions.split(":")

            if word in final_text_list:
                emotion_list.append(emotion)

    # print(emotion_list)

    # method to get the values for sensitive analysis. Using nested methods to get results

    # def sentiment_analysis(text):
    score = SentimentIntensityAnalyzer().polarity_scores(text)
    pos = score["pos"]
    print(f"Positive Score {pos}")
    neg = score["neg"]
    print(f"Negetive Score {neg}")
    if pos>neg:
        print("Positive Sentiment is observed")
    elif neg>pos:
        print("Negetive Sentiment is observed")
    else:
        print("Neutral Sentiment is observed")

    #Polarity Score

    pol = ((pos-neg)/(pos+neg)+ 0.000001)
    print(f"The Polarity score is {pol}")

    # ubjective Score

    subj = ((pos+neg)/(len(text))+ 0.000001)
    print(f"The Subjectivity score is {subj}")

    # Word count on the clean text(removed punctuations and stopwords)

    # def word_count(text):
    # from nltk.tokenize import word_tokenize

    no_of_words = len(word_tokenize(cleaned_text))
    print(f"The Word Count : {no_of_words}")

    # Avg Word length = total no of characters / total no of words

    # def avg_word_len(text):
    # from nltk.tokenize import word_tokenize

    no_of_chars = 0
    for word in word_tokenize(cleaned_text):
        no_of_chars  = no_of_chars+ len(word)

    avg_word_len = no_of_chars / no_of_words
    print(f"Avg_word_length : {avg_word_len}")

    # avg no of words per sentence = no_of_words / no_of_sentences

    # def avg_no_of_words_per_sent(text):
    # from nltk.tokenize import word_tokenize,sent_tokenize

    no_of_sents = len(sent_tokenize(cleaned_text))
    avg_no_of_words_per_sent = (no_of_words / no_of_sents)
    print(f"The Avg no of words per Sentence : {avg_no_of_words_per_sent}")

    # Method to print syllables

    # def syllable_count(word):
    # word = word.lower()

    words=word_tokenize(cleaned_text)
    vowels = "a","e","i","o","u","y"
    no_of_syllables = 0
    for word in words:
        if word[0] in vowels:
            no_of_syllables = no_of_syllables+1

    for index in range (1,len(word)):
        if word[index] in vowels and word[index-1] not in vowels:
            no_of_syllables = no_of_syllables+1

    if word.endswith("e"):
        no_of_syllables = no_of_syllables - 1

    if no_of_syllables == 0:
        no_of_syllables = no_of_syllables+1

    print(f"The No of syllables present:{no_of_syllables}")

    # Method to count the complex numbers

    # def complex_word_count(text):
    # from nltk.tokenize import word_tokenize
    words=word_tokenize(cleaned_text)
    complex_word = 0
    for word in words:
        if (no_of_syllables>2):
            complex_word = complex_word+1

    print(f"The complex word count : {complex_word}")

    # Method for the percentage of complex numbers

    # def percent_complex(text):
    # from nltk.tokenize import word_tokenize

    complex_percent = (complex_word/ no_of_words)*100
    print(f"The Percentage of complex words : {complex_percent}")

    # Fog Index

    # def fog_index(text):
    # avg_sent_length = avg_no_of_words_per_sent()

    fog_read = 0.4*(avg_no_of_words_per_sent/ complex_percent)
    print(f"The Fog Index : {fog_read}")

    # Method to find personal Pronoun Count
    # def personal_pronoun(text):

    count = 0
    if "I" in text:
        pronoun = re.split("I", text)
        count = count+1
        if "us" in text:
            pronoun = re.split("us", text)
            count = count+1
            if "we" in text:
                pronoun = re.split("we", text)
                count = count+1
                if "my" in text:
                    pronoun = re.split("my", text)
                    count = count+1
                    if "ours" in text:
                        pronoun = re.split("ours", text)
                        count = count+1

    print(f"Number of pronouns present: {count}")

with open("abc.txt","r") as f:
        for line in f:
            e = extract(line)
            print(e)


import os
import setuptools

with open("/home/runner/termux-1/keepitrunning/README.md", "r") as fh:
    long_description = fh.read()

with open('/home/runner/termux-1/keepitrunning/requirements.txt') as f:
    required = f.read().splitlines()

setuptools.setup(
    name="keepitrunning",
    version="1.0.0",
    author="jiroawesome",
    description="A simple python library that makes your python website 24/7.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/jiroawesome/keepitrunning",
    project_urls={
        "Bug Tracker": "https://github.com/jiroawesome/keepitrunning/issues",
    },
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    package_dir={"": "src"},
    package_data={'': ['**/*']},
    packages=setuptools.find_packages(where="src"),
    python_requires=">=3.6",
    install_requires=required
)


import csv
from datetime import date, timedelta
from .ApiSheetClient import ApiSheetClient

class HelabaReader:

    def __init__(self):

        # Mapping can not be done as product type is not included in export-file

        self.client = ApiSheetClient("Issuance Data Collection", "Helaba")

        finaldict = {}
        finaldict["date"] = date.today().strftime('%Y-%m-%d')

        resultdict = self.compare()
        finaldict["Zertifikate"] = resultdict

        self.client.updateFile(finaldict)

    '''
    def updateFile(entry):

        fname = "/Users/janickspirig/Desktop/Stats/DZBankStat/results.txt"

        with open(fname, 'a+') as outfile:
            outfile.seek(0, 2)  # end of file
            size = outfile.tell()  # the size...
            outfile.truncate(size - 1)
            outfile.write(',')
            json.dump(entry, outfile)
            outfile.write(']')
            outfile.close()
    '''

    def readData(self, area, date):
        products = []

        if area == "Zeichnungen":
            sub_fname = "Laufende"
        else:
            sub_fname = "Gesamtuebersicht"

        with open("/Users/janickspirig/PycharmProjects/IsuanceDataService/sp-handler/data/Helaba/{} {} {}.csv".format(sub_fname, area, date), "r",
                  encoding='ISO-8859-1') as f:

            reader = csv.reader(f, delimiter=";")
            next(reader)
            for i, line in enumerate(reader):
                if len(line) > 0:
                    product_id = line[1]
                    try:
                        product_type = line[0]
                    except IndexError:
                        product_type = "NotAllocated"
                    products.append([product_id, product_type])
        return products

    def compare(self):
        yesterday = (date.today() - timedelta(days=1)).strftime('%d-%m-%Y')
        today = date.today().strftime('%d-%m-%Y')

        oldProducts = self.readData("Neuemissionen", yesterday)
        newProducts = self.readData("Neuemissionen", today)

        count_dict = {}
        for x in newProducts:
            if not any(x[0] in sl for sl in oldProducts):
                if not x[1] in count_dict.keys():
                    count_dict[x[1]] = {}
                    count_dict[x[1]]['amount'] = 1
                    count_dict[x[1]]['ISINs'] = [x[0]]
                    # product type and then we have the number, so lets do product type as key and then another nested dict with number and examples --> and here at examples we put in some random IDs
                else:
                    count_dict[x[1]]['amount'] = count_dict[x[1]]['amount'] + 1
                    count_dict[x[1]]['ISINs'].append(x[0])
        return count_dict


from __future__ import print_function
import os
import json
import _pickle as cPickle
import numpy as np
import util.utils as utils
import warnings
with warnings.catch_warnings():
    warnings.filterwarnings("ignore",category=FutureWarning)
import h5py
from xml.etree.ElementTree import parse
import torch
from torch.utils.data import Dataset
import tools.compute_softscore
import itertools
import re

COUNTING_ONLY = False

def is_howmany(q, a, label2ans):
    if 'how many' in q.lower() or \
       ('number of' in q.lower() and 'number of the' not in q.lower()) or \
       'amount of' in q.lower() or \
       'count of' in q.lower():
        if a is None or answer_filter(a, label2ans):
            return True
        else:
            return False
    else:
        return False

def answer_filter(answers, label2ans, max_num=10):
    for ans in answers['labels']:
        if label2ans[ans].isdigit() and max_num >= int(label2ans[ans]):
            return True
    return False

def _create_entry(img, question, answer):
    if None!=answer:
        answer.pop('image_id')
        answer.pop('question_id')
    entry = {
        'question_id' : question['question_id'],
        'image_id'    : question['image_id'],
        'image'       : img,
        'question'    : question['question'],
        'answer'      : answer}
    return entry

def _load_dataset(dataroot, name, img_id2val, label2ans):
    """Load entries

    img_id2val: dict {img_id -> val} val can be used to retrieve image or features
    dataroot: root path of dataset
    name: 'train', 'val', 'test-dev2015', test2015'
    """
    question_path = os.path.join(
        dataroot, 'v2_OpenEnded_mscoco_%s_questions.json' % \
        (name + '2014' if 'test'!=name[:4] else name))
    questions = sorted(json.load(open(question_path))['questions'],
                       key=lambda x: x['question_id'])
    if 'test'!=name[:4]: # train, val
        answer_path = os.path.join(dataroot, 'cache', '%s_target.pkl' % name)
        answers = cPickle.load(open(answer_path, 'rb'))
        answers = sorted(answers, key=lambda x: x['question_id'])

        utils.assert_eq(len(questions), len(answers))
        entries = []
        for question, answer in zip(questions, answers):
            utils.assert_eq(question['question_id'], answer['question_id'])
            utils.assert_eq(question['image_id'], answer['image_id'])
            img_id = question['image_id']
            if not COUNTING_ONLY or is_howmany(question['question'], answer, label2ans):
                entries.append(_create_entry(img_id2val[img_id], question, answer))
    else: # test2015
        entries = []
        for question in questions:
            img_id = question['image_id']
            if not COUNTING_ONLY or is_howmany(question['question'], None, None):
                entries.append(_create_entry(img_id2val[img_id], question, None))

    return entries

class VQAFeatureDataset(Dataset):
    def __init__(self, name, dictionary, dataroot='data', adaptive=False):
        super(VQAFeatureDataset, self).__init__()
        assert name in ['train', 'val', 'test-dev2015', 'test2015']

        ans2label_path = os.path.join(dataroot, 'cache', 'trainval_ans2label.pkl')
        label2ans_path = os.path.join(dataroot, 'cache', 'trainval_label2ans.pkl')
        self.ans2label = cPickle.load(open(ans2label_path, 'rb'))
        self.label2ans = cPickle.load(open(label2ans_path, 'rb'))
        self.num_ans_candidates = len(self.ans2label)

        self.dictionary = dictionary
        self.adaptive = adaptive

        self.img_id2idx = cPickle.load(
            open(os.path.join(dataroot, '%s%s_imgid2idx.pkl' % (name, '' if self.adaptive else '36')), 'rb'))

        h5_path = os.path.join(dataroot, '%s%s.hdf5' % (name, '' if self.adaptive else '36'))

        print('loading features from h5 file')
        # with h5py.File(h5_path, 'r') as hf:
        #     self.features = np.array(hf.get('image_features'))
        #     self.spatials = np.array(hf.get('spatial_features'))
        #     if self.adaptive:
        #         self.pos_boxes = np.array(hf.get('pos_boxes'))
        hf = h5py.File(h5_path, 'r')
        self.features = hf.get('image_features')
        self.spatials = hf.get('spatial_features')
        if self.adaptive:
            self.pos_boxes = hf.get('pos_boxes')

        self.entries = _load_dataset(dataroot, name, self.img_id2idx, self.label2ans)
        self.tokenize()
        self.tensorize()
        # self.v_dim = self.features.size(1 if self.adaptive else 2)
        # self.s_dim = self.spatials.size(1 if self.adaptive else 2)
        self.v_dim = self.features.shape[1 if self.adaptive else 2]
        self.s_dim = self.spatials.shape[1 if self.adaptive else 2]

    def tokenize(self, max_length=14):
        """Tokenizes the questions.

        This will add q_token in each entry of the dataset.
        -1 represent nil, and should be treated as padding_idx in embedding
        """
        for entry in self.entries:
            tokens = self.dictionary.tokenize(entry['question'], False)
            tokens = tokens[:max_length]
            if len(tokens) < max_length:
                # Note here we pad in front of the sentence
                padding = [self.dictionary.padding_idx] * (max_length - len(tokens))
                tokens = tokens + padding
            utils.assert_eq(len(tokens), max_length)
            entry['q_token'] = tokens

    def tensorize(self):
        # self.features = torch.from_numpy(self.features)
        # self.spatials = torch.from_numpy(self.spatials)

        for entry in self.entries:
            question = torch.from_numpy(np.array(entry['q_token']))
            entry['q_token'] = question

            answer = entry['answer']
            if None != answer:
                labels = np.array(answer['labels'])
                scores = np.array(answer['scores'], dtype=np.float32)
                if len(labels):
                    labels = torch.from_numpy(labels)
                    scores = torch.from_numpy(scores)
                    entry['answer']['labels'] = labels
                    entry['answer']['scores'] = scores
                else:
                    entry['answer']['labels'] = None
                    entry['answer']['scores'] = None

    def __getitem__(self, index):
        entry = self.entries[index]
        if not self.adaptive:
            # features = self.features[entry['image']]
            # spatials = self.spatials[entry['image']]
            features = torch.from_numpy(self.features[entry['image']])
            spatials = torch.from_numpy(self.spatials[entry['image']])
        else:
            # features = self.features[self.pos_boxes[entry['image']][0]:self.pos_boxes[entry['image']][1],:]
            # spatials = self.spatials[self.pos_boxes[entry['image']][0]:self.pos_boxes[entry['image']][1],:]
            features = torch.from_numpy(
                self.features[self.pos_boxes[entry['image']][0]:self.pos_boxes[entry['image']][1], :])
            spatials = torch.from_numpy(
                self.spatials[self.pos_boxes[entry['image']][0]:self.pos_boxes[entry['image']][1], :])

        question = entry['q_token']
        question_id = entry['question_id']
        answer = entry['answer']
        if None != answer:
            labels = answer['labels']
            scores = answer['scores']
            target = torch.zeros(self.num_ans_candidates)
            if labels is not None:
                target.scatter_(0, labels, scores)
            return features, spatials, question, target
        else:
            return features, spatials, question, question_id

    def __len__(self):
        return len(self.entries)


from importlib import resources

import pytest

from tests.ui_screens.utils import ocr_test_frame

from subot.ui_areas.enchanter.disenchant import SpellDisenchantUI

@pytest.fixture
def spell_disenchant_ui(audio_system_test, config, ocr_engine) -> SpellDisenchantUI:

    return SpellDisenchantUI(audio_system=audio_system_test, config=config, ocr_engine=ocr_engine)

def test_disenchant_ui(audio_system_test, spell_disenchant_ui):

    with resources.path(__package__, 'disenchant_equipped_no_properties.png') as path:
        ocr_test_frame(path, spell_disenchant_ui)
    spell_disenchant_ui.speak_auto()

    assert audio_system_test.last_text.startswith("Ancient Prayer")
    assert "already fully disenchanted" in audio_system_test.last_text
    assert "Equipped" in audio_system_test.last_text

def test_zero_property_spell_gem(audio_system_test, spell_disenchant_ui):

    # test no properties
    with resources.path(__package__, 'disenchant_equipped_fully_disenchanted.png') as path:
        ocr_test_frame(path, spell_disenchant_ui)
    spell_disenchant_ui.speak_auto()
    assert "already fully disenchanted" in audio_system_test.last_text

def test_selected_slot(audio_system_test, spell_disenchant_ui):
    # test disenchant slot UI
    with resources.path(__package__, 'disenchant_slot.png') as path:
        ocr_test_frame(path, spell_disenchant_ui)
    spell_disenchant_ui.speak_auto()

    assert audio_system_test.last_text == "Generous"

    spell_disenchant_ui.speak_interaction()
    assert audio_system_test.last_text.startswith("Zephyr (Melon)")


import socket
import hashlib
import hmac
import json
import logging
from threading import Thread
import threading
import time
from typing import Any

import BRACHA.utils as utils

from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305

RCV_BUFFER_SIZE = 8192
KEY_SIZE = 32
KEY_EXCHANGE = 0  # 1

class AuthenticatedLink:
    def __init__(self, self_id, self_ip, idn, ip, proc):
        self.proc = proc
        self.self_id = self_id  # id of sending process
        self.id = idn  # id of receiving process
        self.self_ip = self_ip
        self.ip = ip
        self.key = {}
        self.sending_port = (
            int("50" + str(self.self_id) + str(self.id))
            if self.self_id < 10 and self.id < 10
            else int("5" + str(self.self_id) + str(self.id))
        )
        self.receiving_port = (
            int("50" + str(self.id) + str(self.self_id))
            if self.self_id < 10 and self.id < 10
            else int("5" + str(self.id) + str(self.self_id))
        )
        self.written = False
        self.bytes_sent = 0

    def key_exchange(self):
        if KEY_EXCHANGE == 1:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.sock:
                self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                while True:
                    # Try Except used to repeat the connection until the other socket is opened again
                    try:
                        self.sock.connect((self.ip, self.sending_port))

                        self.__check(self.id, self.sock)

                        break
                    except ConnectionRefusedError:
                        continue
        else:
            self.key[self.id] = utils.get_key(self.self_id, self.id)

    def receiver(self):
        logging.info("AUTH:Start thread to receive messages...")
        t = Thread(target=self.__receive)
        t.start()

    # This handles the message receive
    # Now the listening port is the concatenation 50/5 - 'receiving process' - 'sending process'
    def __receive(self):
        host = ""  # Symbolic name meaning all available interfaces

        logging.info("AUTH:Port used for receiving: %d", self.receiving_port)

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.s:
            self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.s.bind((host, self.receiving_port))
            self.s.listen(1000)

            while True:
                conn, addr = self.s.accept()

                with conn:
                    received_data = b""
                    while True:
                        try:
                            data = conn.recv(RCV_BUFFER_SIZE)

                            if not data:
                                break
                            received_data += data
                        except ConnectionResetError:
                            print("Connection reset by peer")
                            pass

                    if len(received_data) != 0:
                        parsed_data = {}
                        try:
                            parsed_data = json.loads(received_data.decode())
                        except json.JSONDecodeError:
                            print("Decode Error: data too long")

                        if not self.written:
                            start_time = time.time() * 1000

                            logging.info(
                                "----- EVALUATION CHECKPOINT: message receiving, time: %s -----",
                                start_time,
                            )

                            self.written = True

                        logging.info(
                            "AUTH: <%s, %d> -- sent this data %s",
                            self.ip,
                            self.id,
                            parsed_data,
                        )

                        # Useful for performance evaluation, upon the arrival of the first
                        # message it starts timer to monitor execution time

                        if "MSG" not in parsed_data.keys():
                            self.__add_key(parsed_data)
                            conn.sendall(b"synACK")

                        else:
                            t = Thread(
                                target=self.__deliver,
                                args=(parsed_data, threading.currentThread()),
                            )
                            t.start()

                        logging.info("AUTH:Received DATA: %s", data)

    def __add_key(self, key_dict):
        # self.key[self.id] = utils.get_key(self.self_id, self.id)
        self.key[self.id] = key_dict["KEY"].encode("latin1")

        logging.info(
            "AUTH: <%s, %d> is the one with this key: %s", self.ip, self.id, self.key
        )

    def __check(self, sock, idn):
        if idn not in self.key and self.self_id <= idn:
            self.key[idn] = ChaCha20Poly1305.generate_key()

            key_to_send = {"KEY": self.key[idn].decode("latin1")}
            logging.info("AUTH: Key generated")
            logging.info("AUTH: This is what I am sending: %s", key_to_send)

            data = json.dumps(key_to_send)
            sock.sendall(data.encode())
            temp = sock.recv(RCV_BUFFER_SIZE, 0).decode()

            if temp != "synACK":  # Ack used for synchronization with other process
                return 1

    # Compute the hmac of the message with a key associated to the process with self.id
    # The message is returned as a dictionary: {"MSG": message,"HMAC": hmac, "FLAG": flag}
    # The hmac is computed starting from the concatenation of flag and message
    # Example: flag = "SEND" , message = "Hello" ----> HMAC("SENDHello")
    def __auth(self, sock, message):
        self.__check(sock, self.id)
        mess = {
            "MSG": message["MSG"],
            "HMAC": hmac.new(
                self.key.get(self.id, "Key not found"),
                (message["FLAG"] + message["MSG"]).encode("utf-8"),
                hashlib.sha256,
            ).hexdigest(),
            "FLAG": message["FLAG"],
        }

        return mess

    # The send open a new socket, the port is the concatenation of 50/5- id of sending process - id of receiving process
    # Example: sending_id = 1, receiving_id = 2 ---> port = 5012
    def send(self, message):
        # It uses ternary operator

        logging.info(
            "AUTH: Port used to connect: %d to <%s,%d>",
            self.sending_port,
            self.ip,
            self.id,
        )

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            while True:
                try:
                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                    sock.connect((self.ip, self.sending_port))

                    # Mess is a dictionary
                    mess = self.__auth(sock, message)
                    parsed_data = json.dumps(mess)

                    # split big message into small chunks
                    chunks = [
                        parsed_data[i : i + RCV_BUFFER_SIZE]
                        for i in range(0, len(parsed_data), RCV_BUFFER_SIZE)
                    ]

                    # Send each chunk sequentially
                    for chunk in chunks:
                        data = bytes(chunk, encoding="utf-8")
                        sock.sendall(data)

                        # takes into account byte sent
                        self.bytes_sent += len(data)

                    logging.info("AUTH: %s sent to <%s, %d>", mess, self.ip, self.id)
                    break
                except:
                    continue

    # It checks message authenticity comparing the hmac
    def __check_auth(self, message):
        try:
            temp_hash = hmac.new(
                self.key.get(self.id, "Key not found"),
                (message["FLAG"] + message["MSG"]).encode("utf-8"),
                hashlib.sha256,
            ).hexdigest()
            return temp_hash == message["HMAC"]
        except TypeError as e:
            print("TypeError:", e.args)

    def __deliver(self, message, t):
        flag = message["FLAG"]

        if not self.__check_auth(message):
            logging.info("--- Authenticity check failed for %s", message)
            print("Authenticity check failed")
            return

        message.pop("HMAC", None)

        if flag == "SEND":
            self.proc.deliver_send(message, self.id)
        elif flag == "ECHO":
            self.proc.deliver_echo(message, self.id)
        elif flag == "READY":
            self.proc.deliver_ready(message, self.id)


from pathlib import Path
import sys
from threading import *
from time import *
from record import *

# Explicit imports to satisfy Flake8
from tkinter import Tk, Canvas, Entry, Text, Button, PhotoImage, Label
import tkinter as tk
import tkinter.filedialog # Keep this

# Multithreading context switching every 1.0 seconds
sys.setswitchinterval(1.0)

OUTPUT_PATH = Path(__file__).parent
ASSETS_PATH = OUTPUT_PATH / Path(r"assets/frame0")
print(ASSETS_PATH)

def relative_to_assets(path: str) -> Path:
    return ASSETS_PATH/Path(path)

# Function to record the baseline
def recBaselineFunc():
    addr = entry_1.get("1.0",'end-1c')
    if not addr:
        tk.messagebox.showerror(
            title="Empty Fields!", message="Please enter IP Address.")
        return

    global ip_addr
    ip_addr = "ws://" + addr

    print("Recording Baseline")
    updateConsole("Basline Recorded")
    record_baseline(ip_addr)

# Starts the main program
def startFunc():
    addr = entry_1.get("1.0",'end-1c')
    if not addr:
        tk.messagebox.showerror(
            title="Empty Fields!", message="Please enter IP Address.")
        return

    global ip_addr
    ip_addr = "ws://" + addr

    print("Starting program")
    updateConsole("Starting program")
    global record_app
    global stream_data_app
    record_app.start()
    stream_data_app.start()

# Exit the program
def exitFunc():
    print("Exiting")
    sys.exit()

#########################################################################
# Returns a score based on the acceleration
def score_acc(data):
    baseline_acc_fn = 'baseline_data/baseline_acc.csv'

    x, y, z = [], [], []
    with open(baseline_acc_fn,'r') as csvfile:
        lines = csv.reader(csvfile, delimiter=',')
        for row in lines:
            x.append(float(row[0]))
            y.append(float(row[1]))
            z.append(float(row[2]))

    const = 0.0
    px = (abs(max(x)-min(x)) * const)
    py = (abs(max(y)-min(y)) * const)
    pz = (abs(max(z)-min(z)) * const)

    xmax, xmin = max(x)+px, min(x)-px
    ymax, ymin = max(y)+py, min(y)-py
    zmax, zmin = max(z)+pz, min(z)-pz

    # Score:
    score = 0
    for tx,ty,tz in data:
        ref = 3
        if (tx>xmax or tx<xmin):
            ref -= 1
        if (ty>ymax or ty<ymin):
            ref -= 1
        if (tz>zmax or tz<zmin):
            ref -= 1

        if (ref < 2): # ABNORMAL
            pass
        else: # NORMAL
            score += 1
            pass

    score = (score/len(data)) * 100
    updateScore(score)
    print(score)

# Returns a score based on gyroscope data
# FIXME - not in use
def score_gyr(data):
    baseline_gyr_fn = 'baseline_data/baseline_gyr.csv'

    x, y, z = [], [], []
    with open(baseline_gyr_fn,'r') as csvfile:
        lines = csv.reader(csvfile, delimiter=',')
        for row in lines:
            x.append(float(row[0]))
            y.append(float(row[1]))
            z.append(float(row[2]))

    const = 0.0
    px = (abs(max(x)-min(x)) * const)
    py = (abs(max(y)-min(y)) * const)
    pz = (abs(max(z)-min(z)) * const)

    xmax, xmin = max(x)+px, min(x)-px
    ymax, ymin = max(y)+py, min(y)-py
    zmax, zmin = max(z)+pz, min(z)-pz

    # Score:
    score = 0
    for tx,ty,tz in data:
        ref = 3
        if (tx>xmax or tx<xmin):
            ref -= 1
        if (ty>ymax or ty<ymin):
            ref -= 1
        if (tz>zmax or tz<zmin):
            ref -= 1

        if (ref < 2): # ABNORMAL
            pass
        else: # NORMAL
            score += 1
            pass

    score = (score/len(data)) * 100

# Function to update the score on the ui
def updateScore(chng):
    label_1.config(text = chng)

# Function to update the console
def updateConsole(chng):
    label_2.config(text = chng)
#########################################################################

# Main code for the ui
def ui():
    window = Tk()
    window.geometry("400x550")
    window.configure(bg = "#FFFFFF")

    canvas = Canvas(
        window,
        bg = "#FFFFFF",
        height = 550,
        width = 400,
        bd = 0,
        highlightthickness = 0,
        relief = "ridge"
    )

    canvas.place(x = 0, y = 0)
    canvas.create_rectangle(
        34.0,
        114.0,
        355.0,
        349.0,
        fill="#D9D9D9",
        outline="")

    image_image_1 = PhotoImage(
        file=relative_to_assets("image_1.png"))
    image_1 = canvas.create_image(
        206.0,
        55.0,
        image=image_image_1
    )

    canvas.create_text(
        96.0,
        139.0,
        anchor="nw",
        text="IP Address:",
        fill="#000000",
        font=("Inter Bold", 15 * -1)
    )

    entry_image_1 = PhotoImage(
        file=relative_to_assets("entry_1.png"))
    entry_bg_1 = canvas.create_image(
        242.5,
        149.0,
        image=entry_image_1
    )

    global entry_1
    entry_1 = Text(
        bd=0,
        bg="#F1F1F1",
        fg="#000716",
        highlightthickness=0,
        font=("Helvetica", 7)
    )
    entry_1.place(
        x=191.0,
        y=142.0,
        width=103.0,
        height=12.0
    )

    # Walking Score rectangle
    canvas.create_rectangle(
        95.0,
        402.0,
        306.0,
        525.0,
        fill="#D9D9D9",
        outline="")

    global label_1
    label_1 = Label(
        bd=0,
        bg="#F1F1F1",
        fg="#000716",
        highlightthickness=0,
        text="100"
    )
    label_1.place(
        x=175.0,
        y=450.0,
        width=50.0,
        height=50.0
    )

    global label_2
    label_2 = Label(
        bd=0,
        bg="#F1F1F1",
        fg="#000716",
        highlightthickness=0,
        text=">> Welcome!"
    )
    label_2.place(
        x=100.0,
        y=347.0,
        width=200.0,
        height=30.0
    )

    button_image_1 = PhotoImage(
        file=relative_to_assets("button_1.png"))
    button_1 = Button(
        image=button_image_1,
        borderwidth=0,
        highlightthickness=0,
        command=startFunc,
        relief="flat"
    )
    button_1.place(
        x=126.0,
        y=230.0,
        width=136.35812377929688,
        height=40.0
    )

    button_image_2 = PhotoImage(
        file=relative_to_assets("button_2.png"))
    button_2 = Button(
        image=button_image_2,
        borderwidth=0,
        highlightthickness=0,
        command=recBaselineFunc,
        relief="flat"
    )
    button_2.place(
        x=95.0,
        y=172.0,
        width=199.0,
        height=40.0
    )

    button_image_3 = PhotoImage(
        file=relative_to_assets("button_3.png"))
    button_3 = Button(
        image=button_image_3,
        borderwidth=0,
        highlightthickness=0,
        command=exitFunc,
        relief="flat"
    )
    button_3.place(
        x=152.0,
        y=290.0,
        width=85.0,
        height=34.46666717529297
    )

    canvas.create_text(
        133.0,
        412.0,
        anchor="nw",
        text="Walking Score",
        fill="#000000",
        font=("Inter Bold", 20 * -1)
    )
    window.resizable(False, False)

    window.mainloop()

# Class to start new thread for recording real-time data
class record_APP(Thread):
    def run(self):
        global ip_addr
        record(ip_addr)

# Class to start thread to capture the real-time data
class stream_data_APP(Thread):
    def run(self):
        while True:
            # print(list(LIVE_DATA.queue))
            live_data = list(LIVE_DATA.queue)
            if len(live_data) == REALTIME_SAMPLES:
                score_acc(list(LIVE_DATA.queue))
                # score_gyr(list(LIVE_DATA.queue))
            sleep(0.1)

def main():
    global record_app
    global stream_data_app
    record_app = record_APP(daemon=True)
    stream_data_app = stream_data_APP(daemon=True)

    global ip_addr

    ui()

if __name__ == "__main__":
    main()


from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django import forms
from django.conf.urls import url
from django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import render

from mvs.models import Aanmelding, Vrijwilliger

class AutocompleteOffMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for field_name in self.fields:
            self.fields[field_name].widget.attrs["autocomplete"] = "off"

class VrijwilligerVraagForm(AutocompleteOffMixin, forms.Form):
    url = "vrijwilliger"
    title = "Vrijwilligers"
    description = "Zoals elk jaar zijn we weer op zoek naar vrijwilligers om ons te helpen tijdens de dagen. We kunnen helaas niet zonder. Hebt u tijd om te helpen? Ook als u maar een dag of een dagdeel kunt, bent u van harte welkom."

    aanmelden = forms.ChoiceField(
        label="Kunt u komen helpen?",
        choices=[
            ("ja", "Ja"),
            ("nee", "Nee"),
            ("nee", "Ik heb me al aangemeld"),
        ],
        widget=forms.RadioSelect,
    )

class VrijwilligerForm(AutocompleteOffMixin, forms.ModelForm):
    title = "Vrijwilligers"

    class Meta:
        model = Vrijwilliger
        exclude = []

        labels = {
            "tel": "Telefoonnummer 1",
            "tel2": "Telefoonnummer 2",
            "ehbo": "Heeft u een EHBO diploma?",
            "stage": "Bent u vrijwilliger voor een maatschappelijke stage?",
            "dagen": "Op welke dagen zou u (eventueel) kunnen komen helpen?",
            "taken": "Hebt u een voorkeur voor een bepaalde taak?",
            "eigen_kind": "Indien u een groep wilt begeleiden, wilt u uw eigen kind in de groep? (Geef de naam van de kinderen die u in de groep wil:)",
            "opmerkingen": "Hebt u nog andere opmerkingen?",
        }

        widgets = {
            "dagen": forms.CheckboxSelectMultiple,
            "taken": forms.CheckboxSelectMultiple,
            "geboortedatum": forms.DateInput(attrs={"type": "date"}),
        }

class VrijwilligerInschrijvenForm(VrijwilligerForm):
    url = "vrijwilliger/aanmelden"

    nog_een = forms.BooleanField(
        label="Wilt u nog een vrijwilliger opgeven?", required=False
    )

class AanmeldingBasisForm(AutocompleteOffMixin, forms.ModelForm):
    url = ""
    title = "Mezzeveulespeule Inschrijfformulier"
    heeft_allergien = forms.BooleanField(
        label="Heeft uw kind allergieën of zijn er bijzonderheden?", required=False
    )

    description = "Zijn jullie met meerdere kinderen thuis en willen jullie allemaal meedoen? Dat kan! Vul voor elk kind een apart formulier in. "

    class Meta:
        model = Aanmelding
        fields = [
            "voornaam",
            "achternaam",
            "geslacht",
            "klas",
            "adres",
            "email",
            "tel1",
            "tel2",
            "school",
        ]

        labels = {
            "voornaam": "Wat is zijn/haar voornaam?",
            "achternaam": "Wat is zijn/haar achternaam?",
            "geslacht": "Een jongen of meisje?",
            "klas": "In welke klas zit uw kind?",
            "adres": "Wat is zijn of haar adres?",
            "email": "Wat is uw e-mailadres?",
            "tel1": "Op welk telefoonnummer kunnen we u bereiken voor en tijdens de dagen?",
            "tel2": "Op welk tweede telefoonnummer kunnen we u in noodgevallen ook bellen?",
            "school": "Op welke school zit uw kind?",
        }
        widgets = {"geslacht": forms.RadioSelect}

class AllergienForm(AutocompleteOffMixin, forms.ModelForm):
    url = "allergien"
    title = "Allergieën en bijzonderheden"

    class Meta:
        model = Aanmelding
        fields = ["allergien"]
        labels = {
            "allergien": "Welke allergie heeft uw kind? Of waar moeten we rekening mee houden?"
        }

class GroepsmaatjeForm(AutocompleteOffMixin, forms.ModelForm):
    url = "groepsmaatje"
    title = "Groepsmaatje"
    description = ""

    class Meta:
        model = Aanmelding
        fields = ["groepsmaatje", "groepsmaatje_school"]

        labels = {
            "groepsmaatje": "Bij wie wil uw kind graag in de groep?",
            "groepsmaatje_school": "Op welke school zit dit groepsmaatje?",
        }

class OvernachtingForm(AutocompleteOffMixin, forms.ModelForm):
    url = "overnachting"
    title = "Overnachting voor groep 8"
    description = "Zit uw kind is groep 8? Dan mag hij voor 3,50 euro extra ook blijven overnachten. "

    class Meta:
        model = Aanmelding
        fields = ["overnachting"]
        labels = {"overnachting": "Wil uw kind ook blijven overnachten?"}

class OpmerkingenForm(AutocompleteOffMixin, forms.ModelForm):
    url = "opmerkingen"
    title = "Opmerkingen of vragen?"

    class Meta:
        model = Aanmelding
        fields = ["opmerkingen"]

        labels = {"opmerkingen": "Hebt u nog opmerkingen of vragen?"}

def get_form(url, post=None, initial=None):
    """
    Bepaal correcte formulier
    """
    forms = [
        VrijwilligerInschrijvenForm,
        VrijwilligerVraagForm,
        AanmeldingBasisForm,
        AllergienForm,
        GroepsmaatjeForm,
        OvernachtingForm,
        OpmerkingenForm,
    ]

    for form in forms:
        if form.url == url:
            if hasattr(form, "Meta") and form.Meta.model == Aanmelding:
                return form(post, initial=initial)
            else:
                return form(post)
    raise Http404

def redirect_to(form):
    return HttpResponseRedirect("/inschrijven/{0}".format(form.url))

def signedup_view(request):
    aangemeld_naam = request.session["aangemeld_naam"]
    if request.method == "POST":
        if "nog_een_kind" in request.POST:
            request.session["aanmelding"] = request.session["zelfde_kind"]

        request.session["zelfde_kind"] = {}
        request.session["aangemeld_naam"] = ""
        return redirect_to(AanmeldingBasisForm)

    return render(request, "signedup.html", {"aangemeld_naam": aangemeld_naam})

def signup_view(request, url):

    # Make sure aanmelding exists
    if "aanmelding" not in request.session:
        request.session["aanmelding"] = {}

    # Maak sessie leeg, handige link
    if url == "leeg":
        request.session["aanmelding"] = {}
        return redirect_to(AanmeldingBasisForm)

    # Handle einde

    if request.method == "POST":
        form = get_form(url, post=request.POST)

        if form.is_valid():
            # Copy all values into session
            if hasattr(form, "Meta") and form.Meta.model == Aanmelding:
                for key in form.Meta.fields:
                    request.session["aanmelding"][key] = form.cleaned_data[key]

            request.session.modified = True

            # Redirect to the next page
            if isinstance(form, AanmeldingBasisForm):
                if form.cleaned_data["heeft_allergien"]:
                    return redirect_to(AllergienForm)
                else:
                    return redirect_to(GroepsmaatjeForm)

            elif isinstance(form, AllergienForm):
                return redirect_to(GroepsmaatjeForm)

            elif isinstance(form, GroepsmaatjeForm):
                # Maybe go to Groep 8 page
                if request.session["aanmelding"]["klas"] == "8":
                    return redirect_to(OvernachtingForm)
                else:
                    return redirect_to(VrijwilligerVraagForm)

            elif isinstance(form, OvernachtingForm):
                return redirect_to(VrijwilligerVraagForm)

            elif isinstance(form, VrijwilligerVraagForm):
                if form.cleaned_data["aanmelden"] == "ja":
                    return redirect_to(VrijwilligerInschrijvenForm)
                else:
                    return redirect_to(OpmerkingenForm)
            elif isinstance(form, VrijwilligerInschrijvenForm):

                # Save form
                form.save()
                if form.cleaned_data["nog_een"]:
                    # TODO: Iets laten weten?
                    return redirect_to(VrijwilligerInschrijvenForm)
                else:
                    return redirect_to(OpmerkingenForm)

            elif isinstance(form, OpmerkingenForm):
                print(dict(request.session))

                aanmelding = Aanmelding(**request.session["aanmelding"])
                aanmelding.save()

                # Reset inschrijving
                zelfde_kind = {}
                for key in ["achternaam", "adres", "email", "tel1", "tel2", "school"]:
                    zelfde_kind[key] = request.session["aanmelding"][key]

                request.session["aangemeld_naam"] = (
                    aanmelding.voornaam + " " + aanmelding.achternaam
                )
                request.session["aanmelding"] = {}
                request.session["zelfde_kind"] = zelfde_kind

                # Sla formulier definitief op
                return HttpResponseRedirect("/inschrijven/aangemeld")

        # Not valid POST? Just show errors
    else:
        if url == VrijwilligerInschrijvenForm.url:
            aanmelding = request.session["aanmelding"]
            form = VrijwilligerInschrijvenForm(
                initial={
                    "achternaam": aanmelding["achternaam"],
                    "adres": aanmelding["adres"],
                    "tel": aanmelding["tel1"],
                    "email": aanmelding["email"],
                }
            )
        else:
            form = get_form(url, initial=request.session["aanmelding"])

    # Laat het formulier zien
    return render(request, "signup.html", {"form": form})

@apphook_pool.register
class SignUpHook(CMSApp):
    name = "Aanmeldingsformulier"

    def get_urls(self, page=None, language=None, **kwargs):

        # replace this with the path to your application's URLs module
        return [
            url(r"^aangemeld", signedup_view),
            url(r"^(.*)", signup_view),
        ]


import os
import threading
import inspect
import logging
import pyspark
from pyspark.sql.types import StringType, DoubleType, IntegerType, LongType, ShortType
import numpy as np

import pyarrow
import pyarrow.parquet
import zstandard as zstd

from com.github.qflock.jdbc.api import QflockJdbcService
from com.github.qflock.jdbc.api import ttypes

from metastore_client import HiveMetastoreClient
from py4j.java_gateway import java_import

class QflockThriftJdbcHandler:
    def __init__(self, spark_log_level="INFO",
                 metastore_ip="", metastore_port="", debug_pyspark=False,
                 max_views=4, compression=True):
        self._max_views = max_views
        self._compression = compression
        self._lock = threading.Lock()
        self._connections = {}
        self._pstatements = {}
        self._connection_id = 0
        self._pstatement_id = 0
        self._query_id = 0
        if debug_pyspark:
            self._create_debug_spark()
        else:
            self._create_spark()
        self._spark.sparkContext.setLogLevel(spark_log_level)
        self._metastore_client = HiveMetastoreClient(metastore_ip, metastore_port)
        self._get_tables()
        self._cached_views = {}
        self._table_paths = {}
        self._ds_table_desc = {}
        self._gw = self._spark.sparkContext._gateway
        java_import(self._gw.jvm, "com.github.qflock.datasource.QflockTableDescriptor")
        self._create_views()
        logging.info(f"initialized compression: {compression}")

    def _create_debug_spark(self):
        self._spark = pyspark.sql.SparkSession \
            .builder \
            .appName("qflock-jdbc")\
            .config("spark.driver.maxResultSize", "10g")\
            .config("spark.driver.memory", "20g")\
            .config("spark.executor.memory", "20g")\
            .config("spark.sql.execution.arrow.pyspark.enabled", "true")\
            .config("spark.sql.catalogImplementation", "hive")\
            .config("spark.sql.warehouse.dir", "hdfs://qflock-storage-dc1:9000/user/hive/warehouse3")\
            .config("spark.hadoop.hive.metastore.uris", "thrift://qflock-storage-dc1:9084")\
            .config("spark.jars", "../../spark/extensions/target/scala-2.12/qflock-extensions_2.12-0.1.0.jar")\
            .getOrCreate()

    def _create_spark(self):
        # .enableHiveSupport()\
        # We do not use hive since we create
        # our own temp views with names of the table.
        self._spark = pyspark.sql.SparkSession \
            .builder \
            .appName("qflock-jdbc")\
            .getOrCreate()

    def _get_tables(self):
        client = self._metastore_client.client
        dbs = self._metastore_client.client.get_all_databases()
        tables = []
        logging.info(f"Fetching tables from metastore")
        for db_name in dbs:
            table_names = client.get_all_tables(db_name)
            tables.extend([client.get_table(db_name, table_name)for table_name in table_names])
        self._tables = tables
        logging.info(f"Fetching tables from metastore...Complete")

    def _create_view(self, table, request_id, schema, file_path):
        # Each table view has a request_id to identify it.
        # The request ID will chosen by a call to
        # the table descriptor's fillRequestInfo the by the client
        #
        logging.info(f"Create view for table: {table.tableName} request_id: {request_id}")
        df = self._spark.read \
            .format("qflockDs") \
            .option("format", "parquet") \
            .option("schema", schema)\
            .option("tableName", table.tableName) \
            .option("path", file_path)\
            .option("dbName", table.dbName) \
            .option("requestId", request_id) \
            .load()
        view_name = f"{table.tableName}_{request_id}"
        df.createOrReplaceTempView(view_name)
        self._cached_views[view_name] = {'name': table.tableName, 'request_id': request_id,
                                         'dataframe': df}

    def _get_schema(self, table):
        def convert_col(type):
            if type == "bigint":
                return "long"
            elif type == "double":
                return "double"
            elif type == "string":
                return "string"
            else:
                logging.error(f"unexpected type: {type}")

        # each field in the schema has name:type:nullable
        schema = list(map(lambda col: f"{col.name}:{convert_col(col.type)}:true", table.sd.cols))
        return ",".join(schema)

    def _create_table_views(self, table):
        fs, path = pyarrow.fs.FileSystem.from_uri(table.sd.location)
        file_info = fs.get_file_info(pyarrow.fs.FileSelector(path))
        files = [f.path for f in file_info if f.is_file and f.size > 0]
        file_path = os.path.split(os.path.split(table.sd.location)[0])[0] + files[0]
        self._table_paths[table.tableName] = file_path
        schema = self._get_schema(table)
        f = fs.open_input_file(file_path)
        reader = pyarrow.parquet.ParquetFile(f)
        # Even when the number of row groups is small, a query can generate multiple
        # queries to the same table.  So we must limit to at least the number of
        # requests that will be arriving to us, which is at least the level of parallelism
        # aka, the number of Spark workers.
        view_count = self._max_views
        logging.info(f"found file: {file_path} row_groups:{reader.num_row_groups} views:{view_count}")
        for request_id in range(0, view_count):
            self._create_view(table, request_id, schema, file_path)

        # Tell the datasource about our table and the number of views it has.
        # This table descriptor will be used later to fetch a request id
        # via fillRequestInfo()
        self._gw.jvm.com.github.qflock.datasource.QflockTableDescriptor.addTable(table.tableName, view_count)
        desc = self._gw.jvm.com.github.qflock.datasource.QflockTableDescriptor.getTableDescriptor(table.tableName)
        self._ds_table_desc[table.tableName] = desc
        f.close()

    def _create_views(self):
        for table in self._tables:
            self._create_table_views(table)
            logging.info(f"View creation Complete. {len(self._cached_views.keys())} total views created.")

    def get_query_id(self):
        query_id = self._query_id
        self._query_id += 1
        return query_id

    def exec_query(self, sql, connection):
        self._lock.acquire()
        query_id = self.get_query_id()
        self._lock.release()
        query = sql.replace('\"', "")
        query_stats = connection['properties']['queryStats']
        rg_offset = connection['properties']['rowGroupOffset']
        rg_count = connection['properties']['rowGroupCount']
        table_name = connection['properties']['tableName']

        # get a request_id from the datasource.
        # This will allow us to pass parameters of rg_offset and count
        # down to the datasource, while still querying using an SQL string.
        # Choose the view which represents this request_id
        req_id = self._ds_table_desc[table_name].fillRequestInfo(int(rg_offset), int(rg_count))

        query = query.replace(f" {table_name} ", f" {table_name}_{req_id} ")
        logging.debug(f"query_id: {query_id} req_id: {req_id} table:{table_name} "
                     f"query: {query} ")
        df = self._spark.sql(query)
        df_pandas = df.toPandas()
        num_rows = len(df_pandas.index)
        logging.debug(f"query toPandas() done rows:{num_rows}")
        df_schema = df.schema
        binary_rows = []
        col_type_bytes = []
        col_bytes = []
        comp_rows = []
        col_comp_bytes = []
        if num_rows > 0:
            columns = df.columns
            for col_idx in range(0, len(columns)):
                # data = np_array[:,col_idx]
                data = df_pandas[columns[col_idx]].to_numpy()
                col_name = df_schema.fields[col_idx].name
                data_type = df_schema.fields[col_idx].dataType
                if isinstance(data_type, StringType):
                    new_data1 = data.astype(str)
                    new_data = np.char.encode(new_data1, encoding='utf-8')
                    item_size = new_data.dtype.itemsize
                    num_bytes = len(new_data) * item_size
                    col_bytes.append(num_bytes)
                    if self._compression is True:
                        # logging.debug(f"compressing col:{col_name} type_size:{item_size} rows:{num_rows} bytes: {num_bytes}")
                        new_data = zstd.ZstdCompressor().compress(new_data)
                        col_comp_bytes.append(len(new_data))
                        # logging.debug(f"compressing rows:{num_rows}.  bytes: {num_bytes}:{len(new_data)} Done")
                        raw_bytes = new_data
                        comp_rows.append(raw_bytes)
                    else:
                        raw_bytes = new_data.tobytes()
                        col_comp_bytes.append(len(raw_bytes))
                        binary_rows.append(raw_bytes)
                    col_type_bytes.append(item_size)
                else:
                    new_data = data.byteswap().newbyteorder().tobytes()
                    # new_data = data.tobytes()
                    num_bytes = len(new_data)
                    col_bytes.append(num_bytes)
                    if self._compression is True:
                        # logging.debug(f"compressing col:{col_name} rows:{num_rows} bytes: {num_bytes}")

                        new_data = zstd.ZstdCompressor().compress(new_data)
                        col_comp_bytes.append(len(new_data))
                        comp_rows.append(new_data)
                        # logging.debug(f"compressing rows:{num_rows} bytes: {num_bytes}:{len(new_data)} Done")
                    else:
                        col_comp_bytes.append(len(new_data))
                        binary_rows.append(new_data)
                    col_type_bytes.append(QflockThriftJdbcHandler.data_type_size(data_type))

        stats = query_stats.split(" ")
        if query_stats != "" and len(stats) > 0:
            prevBytes = stats[1].split(":")[1]
            prevRows = stats[2].split(":")[1]
            currentBytes = stats[3].split(":")[1]
            currentRows = stats[4].split(":")[1]
            logging.debug(f"query-done rows:{num_rows} estRows:{currentRows} " +
                         f"estBytes:{currentBytes} " +
                         f"estNoPushBytes:{prevBytes} estNoPushRows:{prevRows} " +
                         f"query: {query}")
        else:
            logging.debug(f"query-done rows:{num_rows} " +
                         f"query: {query}")
        self._ds_table_desc[table_name].freeRequest(req_id)
        # logging.info(f"query-done rows:{num_rows} query: {query}")
        return ttypes.QFResultSet(id=query_id, metadata=self.get_metadata(df_schema),
                                  numRows=num_rows, binaryRows=binary_rows, columnTypeBytes=col_type_bytes,
                                  columnBytes=col_bytes, compressedColumnBytes=col_comp_bytes,
                                  compressedRows=comp_rows)

    def get_connection_id(self):
        current_id = self._connection_id
        self._connection_id += 1
        return current_id

    def createConnection(self, url, properties):
        dbname = url.split(";")[0].lstrip("/")
        self._lock.acquire()
        current_id = self.get_connection_id()
        self._connections[current_id] = {'url': url, 'properties': properties,
                                         'dbname': dbname}
        self._lock.release()
        logging.debug(f"New connection id {current_id} dbname {dbname} url {url} properties {str(properties)}")
        return ttypes.QFConnection(id=current_id)

    def createStatement(self, connection):
        logging.debug(f"createStatement connection id: {connection.id}")
        return ttypes.QFStatement(id=42, sql=None, id_connection=connection.id)

    def get_prepared_statement_id(self):
        current_id = self._pstatement_id
        self._pstatement_id += 1
        return current_id

    def createPreparedStatement(self, connection):
        self._lock.acquire()
        current_id = self.get_prepared_statement_id()
        self._pstatements[current_id] = {'connection': connection}
        self._lock.release()
        logging.debug(f"createPreparedStatement id {current_id} connection id: {connection.id}")
        return ttypes.QFStatement(id=current_id, sql=None, id_connection=connection.id)

    def connection_getstaticmetadata(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug("connection_getstaticmetadata")

    def connection_isvalid(self, connection, timeout):
        """
        Parameters:
         - connection
         - timeout

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_setAutoCommit(self, connection, autoCommit):
        """
        Parameters:
         - connection
         - autoCommit

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getAutoCommit(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug("connection_getAutoCommit::")
        return QflockJdbcService.connection_getAutoCommit_result(success=True)

    def connection_setTransactionIsolation(self, connection, level):
        """
        Parameters:
         - connection
         - level

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getTransactionIsolation(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_setReadOnly(self, connection, readOnly):
        """
        Parameters:
         - connection
         - readOnly

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getReadOnly(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_setCatalog(self, connection, catalog):
        """
        Parameters:
         - connection
         - catalog

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getCatalog(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_setSchema(self, connection, schema):
        """
        Parameters:
         - connection
         - schema

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getSchema(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getCatalogSeparator(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getCatalogTerm(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getSchemaTerm(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getCatalogs(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getSchemas(self, connection, catalog, schemaPattern):
        """
        Parameters:
         - connection
         - catalog
         - schemaPattern

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getTables(self, connection, catalog, schemaPattern, tableNamePattern, types):
        """
        Parameters:
         - connection
         - catalog
         - schemaPattern
         - tableNamePattern
         - types

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getColumns(self, connection, catalog, schemaPattern, tableNamePattern, columnNamePattern):
        """
        Parameters:
         - connection
         - catalog
         - schemaPattern
         - tableNamePattern
         - columnNamePattern

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getSQLKeywords(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getTableTypes(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def connection_getTypeInfo(self, connection):
        """
        Parameters:
         - connection

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def closeConnection(self, connection):
        """
        Parameters:
         - connection

        """
        if connection.id in self._connections:
            del self._connections[connection.id]
            logging.debug(f"successfully closed connection {connection.id}")
        else:
            logging.warning(f"connection id {connection.id} not found")

    def statement_close(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_execute(self, statement, sql):
        """
        Parameters:
         - statement
         - sql

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_executeQuery(self, statement, sql):
        """
        Parameters:
         - statement
         - sql

        """
        logging.debug(f"statement_executeQuery:: statement id: {statement.id} sql: {sql}")
        row = ttypes.QFRow([ttypes.QFValue(isnull=False, val=ttypes.RawVal(integer_val=42))])
        rows = [row]
        parts = [ttypes.QFResultSetMetaDataPart(columnName='fakecol1', columnType='INT64')]
        metadata = ttypes.QFResultSetMetaData(parts)
        return ttypes.QFResultSet(42, rows, metadata)

    def map_data_type(self, data_type):
        if isinstance(data_type, StringType):
            # java.sql.Types.VARCHAR (JdbcUtil.getSchema
            return (12, False)
        elif isinstance(data_type, DoubleType):
            # java.sql.Types.DOUBLE
            return (8, False)
        elif isinstance(data_type, LongType):
            # java.sql.Types.INTEGER
            return (4, False)
        elif isinstance(data_type, IntegerType):
            # java.sql.Types.INTEGER
            return (4, False)
        else:
            print("unknown type")
            raise Exception(f"unkown type {data_type}")

    def get_metadata(self, df_schema):
        parts = []
        for field in df_schema.fields:
            (columnType, signed) = self.map_data_type(field.dataType)
            parts.append(ttypes.QFResultSetMetaDataPart(columnName=field.name,
                                                        columnType=columnType,
                                                        columnLabel=field.name,
                                                        signed=signed))
        metadata = ttypes.QFResultSetMetaData(parts)
        return metadata

    def map_value(self, data_type, value):
        if isinstance(data_type, StringType):
            return ttypes.RawVal(string_val=value)
        elif isinstance(data_type, DoubleType):
            return ttypes.RawVal(double_val=value)
        elif isinstance(data_type, LongType):
            return ttypes.RawVal(integer_val=value)
        elif isinstance(data_type, IntegerType):
            return ttypes.RawVal(integer_val=value)
        else:
            print("unknown type")
            raise Exception(f"unknown type {data_type}")

    @classmethod
    def data_type_size(cls, data_type):
        if isinstance(data_type, DoubleType):
            return 8
        elif isinstance(data_type, LongType):
            return 8
        elif isinstance(data_type, IntegerType):
            return 4
        elif isinstance(data_type, ShortType):
            return 2
        else:
            # String also falls in this case.  We need to determine size per string.
            raise Exception(f"unknown type {data_type}")

    def statement_getResultSet(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_getUpdateCount(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_getResultSetType(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_cancel(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_getWarnings(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_clearWarnings(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_getMaxRows(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_setMaxRows(self, statement, max):
        """
        Parameters:
         - statement
         - max

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_getQueryTimeout(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def statement_setQueryTimeout(self, statement, seconds):
        """
        Parameters:
         - statement
         - seconds

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_close(self, statement):
        """
        Parameters:
         - statement

        """
        if statement.id in self._pstatements:
            del self._pstatements[statement.id]
            logging.debug(f"successfully closed preparedStatement {statement.id}")
        else:
            logging.warning(f"preparedStatement id {statement.id} not found")

    def preparedStatement_execute(self, statement, sql):
        """
        Parameters:
         - statement
         - sql

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_executeQuery(self, statement, sql):
        """
        Parameters:
         - statement
         - sql

        """
        connection_id = self._pstatements[statement.id]['connection'].id
        connection = self._connections[connection_id]
        logging.debug(f"preparedStatement_executeQuery:: statement id: {statement.id} conn id: {connection_id} " +\
                     f" offset:{connection['properties']['rowGroupOffset']} " +\
                     f" count:{connection['properties']['rowGroupCount']} " +\
                     f" tableName:{connection['properties']['tableName']} sql: {sql}")
        # row = ttypes.QFRow([ttypes.QFValue(isnull=False, val=ttypes.RawVal(integer_val=42))])
        # rows = [row]
        # # 4 = java.sql.Types.INTEGER (JdbcUtil.getSchema
        # columnName = 'fakecol1'
        # parts = [ttypes.QFResultSetMetaDataPart(columnName=columnName, columnType=4,
        #                                         columnLabel=columnName, signed=False)]
        # metadata = ttypes.QFResultSetMetaData(parts)
        # return ttypes.QFResultSet(42, rows, metadata)
        self._spark.sql(f"USE {connection['dbname']}")
        return self.exec_query(sql, connection)

    def preparedStatement_getResultSet(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_getUpdateCount(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_getResultSetType(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_cancel(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_getWarnings(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_clearWarnings(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_getMaxRows(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_setMaxRows(self, statement, max):
        """
        Parameters:
         - statement
         - max

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_getQueryTimeout(self, statement):
        """
        Parameters:
         - statement

        """
        logging.debug(inspect.currentframe().f_code.co_name)

    def preparedStatement_setQueryTimeout(self, statement, seconds):
        """
        Parameters:
         - statement
         - seconds

        """
        logging.debug(inspect.currentframe().f_code.co_name)


from itertools import product

import utils

class Seating:
    def __init__(self, pattern):
        self.width = len(pattern[0].strip())
        self.height = len(pattern)
        self.state_map = {}
        for y, line in enumerate(pattern):
            for x, seat in enumerate(line.strip()):
                self.state_map[(x, y)] = seat

    def update_state_1(self):
        new_state = {}
        for x in range(self.width):
            for y in range(self.height):
                prev_state = self.state_map[(x, y)]
                adjacent_occupied = sum(
                    [self.state_map.get((adj_x, adj_y), ".") == "#"
                     for (adj_x, adj_y) in adjacent_seats(x, y)])
                if (prev_state == "L") and (adjacent_occupied == 0):
                    new_state[(x, y)] = "#"
                elif (prev_state == "#") and (adjacent_occupied >= 4):
                    new_state[(x, y)] = "L"
                else:
                    new_state[(x, y)] = prev_state
        self.state_map = new_state

    def update_state_2(self):
        new_state = {}
        for x in range(self.width):
            for y in range(self.height):
                prev_state = self.state_map[(x, y)]
                visible_occupied = sum(
                    [self.state_map.get((adj_x, adj_y), ".") == "#"
                     for (adj_x, adj_y) in self.find_visible_seats(x, y)])
                if (prev_state == "L") and (visible_occupied == 0):
                    new_state[(x, y)] = "#"
                elif (prev_state == "#") and (visible_occupied >= 5):
                    new_state[(x, y)] = "L"
                else:
                    new_state[(x, y)] = prev_state
        self.state_map = new_state

    def find_visible_seats(self, x, y):
        visible_seats = []
        for (x_dir, y_dir) in [
                (0, -1),
                (1, -1),
                (1, 0),
                (1, 1),
                (0, 1),
                (-1, 1),
                (-1, 0),
                (-1, -1)]:
            cur_x, cur_y = x + x_dir, y + y_dir
            while ((cur_x >= 0)
                   and (cur_x < self.width)
                   and (cur_y >= 0)
                   and (cur_y < self.height)):
                if self.state_map[(cur_x, cur_y)] in ("L", "#"):
                    visible_seats.append((cur_x, cur_y))
                    break
                cur_x += x_dir
                cur_y += y_dir
        return visible_seats

def adjacent_seats(x, y):
    return [(x, y - 1),
            (x + 1, y - 1),
            (x + 1, y),
            (x + 1, y + 1),
            (x, y + 1),
            (x - 1, y + 1),
            (x - 1, y),
            (x - 1, y - 1)]

def stabilize_seating_1(pattern):
    seating = Seating(pattern)
    prev_state = seating.state_map.copy()
    while True:
        seating.update_state_1()
        new_state = seating.state_map
        if prev_state == new_state:
            break
        prev_state = new_state.copy()
    return sum([seating.state_map.get((x, y), ".") == "#"
                for x, y in product(range(seating.width),
                                    range(seating.height))])

def stabilize_seating_2(pattern):
    seating = Seating(pattern)
    prev_state = seating.state_map.copy()
    while True:
        seating.update_state_2()
        new_state = seating.state_map
        if prev_state == new_state:
            break
        prev_state = new_state.copy()
    return sum([seating.state_map.get((x, y), ".") == "#"
                for x, y in product(range(seating.width),
                                    range(seating.height))])

if __name__ == "__main__":
    parsed_strings = utils.parse_file_lines("day11_input.txt", str)
    print("Part 1: {}".format(stabilize_seating_1(parsed_strings)))
    print("Part 2: {}".format(stabilize_seating_2(parsed_strings)))


import azure.functions as func
from azure.identity import EnvironmentCredential
from azure.mgmt.automation import AutomationClient
import json
import logging
import os
import requests
from urllib.parse import urlparse, parse_qs

# env variables used by the SDK to access the Automation account
SUBSCRIPTION_ID = os.environ.get("AZURE_SUBSCRIPTION_ID", None)
GROUP_NAME = os.environ.get("AUTOMATION_GROUP_NAME", None)
ACCOUNT_NAME = os.environ.get("AUTOMATION_ACCOUNT_NAME", None)

def get_status(client, id):
    job = client.job.get(GROUP_NAME, ACCOUNT_NAME, id)
    response = {'id': id, 'status': job.status, 'exception': job.exception}
    return response

def get_output(client, id):
    streams = client.job_stream.list_by_job(GROUP_NAME, ACCOUNT_NAME, id)

    output = []
    warnings = []
    errors = []

    for job_stream in streams:
        if job_stream.stream_type == 'Output':
            output.append(job_stream.summary)
        if job_stream.stream_type == 'Warning':
            warnings.append(job_stream.summary)
        if job_stream.stream_type == 'Error':
            errors.append(job_stream.summary)

    response = {'output': output, 'warnings': warnings, 'errors': errors}
    return response

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info(f'HTTP trigger processed a request. Method: {req.method}, URL: {req.url}')

    action = req.route_params.get('action')
    id = req.route_params.get('id')
    response = None

    try:
        if action == 'submit':
            try:
                webhook_data = req.get_json()
            except ValueError:
                webhook_data = None

            # JSON sent in the request body must include the "webhookName" property to locate the webhook URL
            webhook_name = webhook_data.get('webhookName', '')
            url = urlparse(os.environ.get('WEBHOOK_'+webhook_name, None))

            webhook_url = f"https://{url.netloc}{url.path}"
            webhook_token = parse_qs(url.query)['token'][0]
            webhook_params = {
                # the Azure portal provides the webhook URL with URL encoding, so decode here
                'token': webhook_token
            }

            webhook_response = requests.request('POST', webhook_url, params=webhook_params, json=webhook_data)
            # response to the webhook POST is JSON formatted containing the Automation job ID
            response = webhook_response.text

        elif action == 'status':
            if id != None:
                client = AutomationClient(credential=EnvironmentCredential(), subscription_id=SUBSCRIPTION_ID)
                status_response = get_status(client, id)
                response = json.dumps(status_response)
                client.close()

        elif action == 'output':
            if id != None:
                client = AutomationClient(credential=EnvironmentCredential(), subscription_id=SUBSCRIPTION_ID)
                output_response = get_output(client, id)
                response = json.dumps(output_response)
                client.close()

        elif action == 'details':
            if id != None:
                client = AutomationClient(credential=EnvironmentCredential(), subscription_id=SUBSCRIPTION_ID)
                status_response = get_status(client, id)
                output_response = get_output(client, id)

                response = json.dumps(status_response | output_response)
                client.close()
        else:
            status_code = 404

        return func.HttpResponse(response, status_code=200, mimetype='application/json')

    except Exception as e:
        response = json.dumps({'error': repr(e)})
        return func.HttpResponse(response, status_code=500, mimetype='application/json')


#-----<Step1: Intstall Required Packages>---------
import streamlit as st
import pickle
import numpy as np
from sklearn import metrics
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier as knn
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
import pickle
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import precision_score,recall_score,f1_score

# Title and Subheader
from PIL import Image
image = Image.open('fitbod_logo2.jpg')
st.image(image, width=1,caption=None,
    use_column_width=True)
st.title("Fitbod Helper: Predict Churn User")
st.header("Step0: Understand Dataset")

image = Image.open('new_churn.jpg')
st.image(image, width=1,caption='New User VS. Churn User',
    use_column_width=True)

# Load the pipeline and data
X_test = pickle.load(open('X_test.sav', 'rb'))
y_test = pickle.load(open('y_test.sav', 'rb'))
workoutData = pickle.load(open('workoutData.sav', 'rb'))
replace_cols=['churn_user']
for i in replace_cols :
    y_test[i]  = y_test[i].replace({1.0 : 1, 0.0:0})

pipe1 = pickle.load(open('pipe_KNN.sav', 'rb'))
knn_pre_class = pipe1.predict(X_test)
knn_pre_prob = pipe1.predict_proba(X_test)
#score1 = pipe1.score(X_test, y_test)
score1 = 0.688
#auc1 = cross_val_score(pipe1, X_test, y_test, scoring='roc_auc', cv=10)
# precision_KNN= precision_score(y_true=y_test, y_pred=knn_pre_class)
precision_KNN = 0.500
# recall_KNN=recall_score(y_true=y_test, y_pred=knn_pre_class)
recall_KNN = 0.200
#f1_KNN=f1_score(y_true=y_test, y_pred=knn_pre_class)
f1_KNN = 0.286

pipe2 = pickle.load(open('pipe_RF.sav', 'rb'))
rf_pre_class = pipe2.predict(X_test)
rf_pre_prob = pipe2.predict_proba(X_test)
#score2 = pipe2.score(X_test, y_test)
score2=0.938
#auc1 = cross_val_score(pipe1, X_test, y_test, scoring='roc_auc', cv=10)
#precision_RF= precision_score(y_true=y_test, y_pred=rf_pre_class)
precision_RF=0.500
#recall_RF=recall_score(y_true=y_test, y_pred=rf_pre_class)
recall_RF= 0.400
#f1_RF=f1_score(y_true=y_test, y_pred=rf_pre_class)
f1_RF=0.444

pipe3 = pickle.load(open('pipe_LR.sav', 'rb'))
lr_pre_class = pipe3.predict(X_test)
lr_pre_prob = pipe3.predict_proba(X_test)
#score3 = pipe3.score(X_test, y_test)
score3=0.625
#auc1 = cross_val_score(pipe1, X_test, y_test, scoring='roc_auc', cv=10)
#precision_LR= precision_score(y_true=y_test, y_pred=lr_pre_class)
precision_LR=0.400
#recall_LR=recall_score(y_true=y_test, y_pred=lr_pre_class)
recall_LR = 0.400
#f1_LR=f1_score(y_true=y_test, y_pred=lr_pre_class)
f1_LR = 0.400

clf_compare ={'Accuracy':[score1,score2,score3],
                     'precision':[precision_KNN,precision_RF,precision_LR],
                     'recall':[recall_KNN,recall_RF,recall_LR],
                     'F1 Score':[f1_KNN,f1_RF,f1_LR]}
clf_compare = pd.DataFrame(clf_compare)
clf_compare.index=['KNN','Random Forest','Logistic Regression']

if st.checkbox('Show User Workout History Data (original)--->>>'):
    st.write(workoutData.head())
uploaded_file = st.file_uploader("Choose a CSV file in the Workout History Format", type="csv")
st.set_option('deprecation.showfileUploaderEncoding', False)

if uploaded_file is not None:
    data = pd.read_csv(uploaded_file)
    st.write(data)

if st.checkbox('Show Processed Data (Model Inputs)--->>>'):
    st.write(X_test.head())

def test_demo(index):
    values = X_test.iloc[index]
    image = Image.open('user3.png')
    st.sidebar.image(image, width=1,caption='User Workout History Portrait',
    use_column_width=True)
    # Create User Input Data in the sidebar/text
    active_days = st.sidebar.slider("How Many Days User Has Workouted with Fitbod?")
    workout_times = st.sidebar.slider("What's the Total Workout Times?")
    workout_per_day = st.sidebar.slider("What's the Workout Times per Day?")
    volume_total = st.sidebar.text_input("What's the Total Exercise Volume on Fitbod?")
    volume_per_day = st.sidebar.slider("Volume(Reps) per Day?")
    intensity_total = st.sidebar.text_input("Total Intensity(Weight)?")
    intensity_per_day = st.sidebar.slider("Intensity(Weight) per Day?")
    favorite_exercise_0 = st.sidebar.selectbox("User's Most Frequently Chosen Exercise?", workoutData.exerciseName.unique().tolist(),key='2')
    dic = {'Barbell Bench Press':0.22, 'Dumbbell Bench Press':0.33, 'Dumbbell Bench Press':0.307, 'Close-Grip Bench Press':0.57,
    'Deadlift':0.3077, 'Dumbbell Lunge':0.4286, 'Dumbbell Shoulder Press':0.50, 'Dumbbell Row':0.6, 'Dumbbell Bent Over Row':0.4
    }
    favorite_exercise= dic[favorite_exercise_0]
    most_recent_exercise_0 = st.sidebar.selectbox("User's Latest Chosen Exercise?",workoutData.exerciseName.unique().tolist(),key='2')
    most_recent_exercise=dic[most_recent_exercise_0]

    stay_days = st.sidebar.slider("Total Days User Has Registered on Fitbod?")
    active_extent= st.sidebar.slider("User's Active Extent?",min_value=0.00, max_value=1.00, step=0.01)
    last_to_now= st.sidebar.slider("How Many Days Went since User's Latest Workout?")
    high_volume_user = st.sidebar.slider("Whether User is High Volume?")
    high_intensity_user = st.sidebar.slider("Whether User is High Intensity User?")
    high_active_user = st.sidebar.slider("Whether User is Highly Active?")

    #Print the prediction result
    st.balloons()
    st.header("Step1: Choose Model")
    if st.checkbox('See the model performance comparison before choosing your favorite one :)'):
        st.write(clf_compare)
        st.write('               🎉 Random Forest Wins the Best AUC Score！！    ')
        image = Image.open('model_AUC.jpg')
        st.image(image, width=1,caption='AUC comparison of 3 Trained Models (Examples)',
    use_column_width=True)
    alg = ['KNN', 'Random Forest', 'Logistic Regression']
    classifier = st.selectbox('Which model do you want to choose for prediction?', alg)
    st.header("Step2: See Machine Learning prediction for this user!")
    dic2={1:'Attention! This is potential churn user!',0:'Congras! This user will stay in Fitbod in the prediction period!'}

    if classifier == 'KNN':
        #pip1 = pickle.load(open('pipe_KNN.sav', 'rb'))
        user_prediction_data = np.array([active_days,
       workout_times, workout_per_day, volume_total, volume_per_day,
       intensity_total, intensity_per_day, favorite_exercise,
       most_recent_exercise, stay_days, active_extent, last_to_now,
       high_volume_user, high_intensity_user, high_active_user]).reshape(1,15)

        res = pipe1.predict_proba(user_prediction_data)
        churn = pipe1.predict(user_prediction_data)
        st.write('According to your input, the churn rate is predicted to be', res[:,1])
        if churn ==0:
            st.write('🎉Congras! Our model suggests that this user will stay in Fitbod for the prediction period!')
        elif churn==1:
            st.write('😢Attention! This is a potential churn user!')
        st.text('Notice: the recall of this model means',)
        image = Image.open('knn_recall.jpg')
        st.image(image, width=1,
    use_column_width=True)
        #st.write('Recall: ', recall_KNN)

        #st.write('Confusion Matrix: ', cm)

    elif classifier == 'Random Forest':
        #pip2 = pickle.load(open('pipe_RF.sav', 'rb'))
        user_prediction_data = np.array([active_days,
       workout_times, workout_per_day, volume_total, volume_per_day,
       intensity_total, intensity_per_day, favorite_exercise,
       most_recent_exercise, stay_days, active_extent, last_to_now,
       high_volume_user, high_intensity_user, high_active_user]).reshape(1,15)

        res = pipe2.predict_proba(user_prediction_data)
        churn = pipe2.predict(user_prediction_data)
        st.write('According to your input, the churn rate is predicted to be', res[:,1])
        if churn ==0:
            st.write('🎉Congras! Our model suggests that this user will stay in Fitbod for the prediction period!')
        elif churn==1:
            st.write('😢Attention! This is a potential churn user!')
        st.text('Notice: the recall of this model means',)
        image = Image.open('rf_lr_recall.jpg')
        st.image(image, width=1,
    use_column_width=True)

        image = Image.open('rf_feature.jpg')
        st.image(image, width=1,caption='Feature Importance for Random Forest',
    use_column_width=True)

        #st.write('Confusion Matrix: ', cm)

    elif classifier == 'Logistic Regression':
        #if st.checkbox('See the interpretation of model--->>>'):
            #image = Image.open('LR_feature_importance.jpg')
            #st.image(image, width=1,caption=None, use_column_width=True)
        user_prediction_data = np.array([active_days,
       workout_times, workout_per_day, volume_total, volume_per_day,
       intensity_total, intensity_per_day, favorite_exercise,
       most_recent_exercise, stay_days, active_extent, last_to_now,
       high_volume_user, high_intensity_user, high_active_user]).reshape(1,15)

        res = pipe3.predict_proba(user_prediction_data)
        churn = pipe3.predict(user_prediction_data)
        st.write('According to your input, the churn rate is predicted to be', res[:,1])
        if churn ==0:
            st.write('🎉Congras! Our model suggests that this user will stay in Fitbod for the prediction period!')
        elif churn==1:
            st.write('😢Attention! This is a potential churn user!')
        st.text('Notice: the recall of this model means',)
        image = Image.open('rf_lr_recall.jpg')
        st.image(image, width=1,
    use_column_width=True)

        image = Image.open('LR_feature.png')
        st.image(image, width=1,caption='Feature Importance for Logistic Regression',
    use_column_width=True)
        #st.write('Confusion Matrix: ', cm)
number = st.text_input('Choose sample from dataset (0 - 200):', 0)  # Input the index number
test_demo(int(number))  # Run the test function