import time
import pandas as pd
import numpy as np

CITY_DATA = { 'chicago': 'chicago.csv',
              'new york city': 'new_york_city.csv',
              'washington': 'washington.csv',
              'chi': 'chicago.csv',
              'nyc': 'new_york_city.csv',
              'wash': 'washington.csv'
            }

def get_filters():
    """
    Asks user to specify a city, month, and day to analyze.

    Returns:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    """
    print("Hello! Let\'s explore some US bikeshare data!")
    # Get user input for city (chicago, new york city, washington).
    city=""
    while city not in CITY_DATA.keys():
        city = input("Enter the city name (chicago, new york city, washington): ").lower()
    print("Great!  Data is from {}.\n".format(city).title())

    # Get user input for month (all, january, february, ... , june)
    month=""
    while month not in ['all', 'jan', 'feb', 'mar', 'apr', 'may', 'jun']:
        month = input("Enter the month abbreviation(all, jan, feb, mar, ... , jun): ").lower()

    # Get user input for day of week (all, monday, tuesday, ... sunday)
    day = ""
    while day not in ["sun", "mon", "tue", "wed", "thu", "fri", "sat", "all"]:
        day = input("Enter the abbreviation for the day of week (all, sun, mon, tue, wed,...sat): ").lower()

    print('-'*40)
    return city, month, day

def load_data(city, month, day):
    """
    Loads data for the specified city and filters by month and day if applicable.

    Args:
        (str) city - name of the city to analyze
        (str) month - name of the month to filter by, or "all" to apply no month filter
        (str) day - name of the day of week to filter by, or "all" to apply no day filter
    Returns:
        df - Pandas DataFrame containing city data filtered by month and day
    """

    months = {'all':0,'jan':1,'feb':2,'mar':3,'apr':4,'may':5,'jun':6}
    df = pd.read_csv(CITY_DATA[city])
    df['Start Time'] = pd.to_datetime(df['Start Time'])
    df['month'] = df['Start Time'].dt.month
    if months[month] > 0:
        df=df[df['month']==months[month]]

    days = {"all":"All","sun":"Sunday", "mon":"Monday", "tue":"Tuesday", "wed":"Wednesday", "thu":"Thursday", "fri":"Friday", "sat":"Saturday"}
    df['weekday_name'] = df['Start Time'].dt.weekday_name
    if days[day]!="All":
        df=df[df['weekday_name']==days[day]]

    return df

def time_stats(df):
    """Displays statistics on the most frequent times of travel."""

    print('\nCalculating The Most Frequent Times of Travel...\n')
    start_time = time.time()

    # Display the most common month
    df['month_name'] = df['Start Time'].dt.month_name()
    print('The most common month is: {}.'.format(df['month_name'].mode()[0]))

    # Display the most common day of week
    df['day_of_week'] = df['Start Time'].dt.weekday_name
    print('The most common day of the week is: {}.'.format(df['weekday_name'].mode()[0]))

    # Display the most common start hour
    df['hour'] = df['Start Time'].dt.hour
    print('The most common start hour is: {}:00.'.format(df['hour'].mode()[0]))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def station_stats(df):
    """Displays statistics on the most popular stations and trip."""

    print("\nCalculating The Most Popular Stations and Trip...\n")
    start_time = time.time()

    # Display most commonly used start station
    print("The most commonly used start station is: ", df['Start Station'].mode()[0])

    # Display most commonly used end station
    print("The most commonly used end station is: ", df['End Station'].mode()[0])

    # Display most frequent combination of start station and end station trip
    print("The most commonly used combination of start and end station is: \n{}".format(df.groupby(['Start Station', 'End Station']).size().nlargest(1)))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def trip_duration_stats(df):
    """Displays statistics on the total and average trip duration."""

    print('\nCalculating Trip Duration...\n')
    start_time = time.time()

    # TO DO: display total travel time
    import datetime
    print("The total travel time is:",str(datetime.timedelta(seconds=int(df['Trip Duration'].sum()))))

    # TO DO: display mean travel time
    print("The average travel time is: ",str(datetime.timedelta(seconds=int(df['Trip Duration'].mean().sum()))))

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def user_stats(df):
    """Displays statistics on bikeshare users."""

    print('\nCalculating User Stats...\n')
    start_time = time.time()

    # TO DO: Display counts of user types
    print("User Type Counts:")
    print(df['User Type'].value_counts())

    # TO DO: Display counts of gender
    if "Gender" in df.columns:
        print("\nGender Type Counts:")
        print(df['Gender'].value_counts())
    else:
        print("\nGender is not found in the data.\n")

    # TO DO: Display earliest, most recent, and most common year of birth
    if "Birth Year" in df.columns:
        print("\nThe earliest birth year is: ", df['Birth Year'].min())
        print("The most recent birth year is: ", df['Birth Year'].max())
        print("The most common birth year is: ", df['Birth Year'].mode()[0])
    else:
        print("\nBirth Year is not found in the data.\n")

    print("\nThis took %s seconds." % (time.time() - start_time))
    print('-'*40)

def main():
    while True:
        city, month, day = get_filters()
        df = load_data(city, month, day)

        time_stats(df)
        station_stats(df)
        trip_duration_stats(df)
        user_stats(df)

        i=0
        while input("\nWould you like to see 5 lines of raw data (yes or no)?\n").lower() == 'yes':
                print(df[i:i+5])
                i+=5

        restart = input('\nWould you like to restart? Enter yes or no.\n')
        if restart.lower() != 'yes':
            break

if __name__ == "__main__":
	main()


import numpy as np
import pickle
import pandas as pd
#from flasgger import Swagger
import streamlit as st

from PIL import Image

#app=Flask(__name__)
#Swagger(app)
filename = 'restaurant-review.pkl'
classifier = pickle.load(open(filename, 'rb'))
tfidf = pickle.load(open('tfidf-transform.pkl','rb'))

#@app.route('/')
def welcome():
    return "Welcome All"

#@app.route('/predict',methods=["Get"])
def predict_note(message):

    data = [message]
    vect = tfidf.transform(data).toarray()
    prediction=classifier.predict(vect)
    print(prediction)
    return prediction

def main():
    st.title("Restaurant Review Classifier")
    st.subheader('TFIFD Vectorizer')
    st.write('This project is based on Naive Bayes Classifier')
    html_temp = """

Restaurant Review Classifier ML App

    """
    st.markdown(html_temp,unsafe_allow_html=True)
    message = st.text_area("Enter Text","Type Here ..")

    result=""
    if st.button("Predict"):
        result=predict_note(message)
    st.success('The output is {}'.format(result))

if __name__=='__main__':
    main()


from django import forms
import material as M
from captcha.fields import ReCaptchaField

class ContactForm(forms.Form):
    layout = M.Layout(M.Row('contact_name', 'contact_email'),
                      M.Row('content'),
                      M.Row('captcha')
                      )
    captcha = ReCaptchaField()
    contact_name = forms.CharField(required=False, label="Navn")
    contact_email = forms.EmailField(required=False, label="E-post")
    content = forms.CharField(required=True, widget=forms.Textarea, label="Melding")


import logging

class LinkedList(object):
    """
    A linked list implementation, with the following attributes
     - Singly linked
     - First in, first out
     - New elements added to end of list
     - Elements removed from beginning of list
    API roughly based on https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html
    """

    def __init__(self, iterable_input=None):
        """
        Initialize and return an instance of the data structure.

        :param iterable_input: Add elements from iterable to the data structure. If iterable is ordered, elements will be in
        that order
        """
        self.head = None
        self.tail = None
        self.size = 0

        if iterable_input is not None:
            logging.info(f'Creating data structure from iteratble: {iterable_input}')

            for element in iterable_input:
                logging.info(f'Adding element {element} to data structure')
                self.add(element)

    def add(self, element):
        """
        Add the specified element to the end of the data structure
        :param element:
        :type element: object
        :return: None
        :rtype: None
        """
        logging.info(
            f'Adding element: {element} to data structure with head: {self.head}, tail: {self.tail} and size: {self.size}')

        # Reference variables
        new_node = LinkedListNode(element)

        # If no elements in data structure, initialize head and tail
        if self.size <= 0:
            logging.info('')
            self.head = new_node
            self.tail = new_node

        # Else, if elements in data structure already, add to old tail set new element as tail
        else:
            self.tail.next = new_node
            self.tail = new_node

        # Increment size
        self.size += 1

        logging.info(f'Added element: {element} to data structure with head: {self.head}, tail: {self.tail} '
                     f'and size: {self.size}')
        return None

    def remove(self):
        """
        Remove the first element from the data structure, and return it. If the data structure is empty, then this will
        raise a ValueError.

        :raises: ValueError
        :return: The first object in the data structure, if there is one
        :rtype: object
        """
        # Reference variables
        element = None

        # If no elements in data structure, raise ValueError
        if self.tail is None:
            raise ValueError('No elements in data structure to remove')

        # Else remove element and update points
        else:
            # If element is head and tail
            if self.size == 1:
                element = self.head.data
                self.head = None
                self.tail = None
            # If element is head, but not tail
            else:
                element = self.head.data
                self.head = self.head.next

        # Decrement size
        self.size -= 1
        return element

    def remove_element(self, element=None):
        """
        Remove the specified element from the data structure. If the specified element is not in the data structure
        (or the data structure is empty), then this will raise a ValueError.

        :param element: The element to be removed
        :type element: object
        :raises: ValueError
        :return: None
        :rtype: None
        """
        # If no elements in data structure, raise ValueError
        if self.tail is None:
            raise ValueError('No elements in data structure to remove')

        # Else iterate through elements until we find the right one
        else:
            cursor = self.head
            cursor_next = self.head.next
            while cursor is not None:
                # Check cursor for element. Can only happen when cursor is head.
                if cursor.data == element:
                    # Remove the current head
                    self.head = cursor_next
                    self.size -= 1
                    return None
                # Check cursor_next for element
                if cursor_next is not None and cursor_next.data == element:
                    # Remove cursor_next
                    new_next = cursor_next.next
                    cursor.next = new_next
                    self.size -= 1
                    return None

                # If element not found, update cursor and cursor_next
                cursor = cursor_next
                cursor_next = cursor.next

        # If we reach the end without finding the element, it is not in the data structure. Return ValueError
        raise ValueError('Element not in data structure')

        return None

    def peak(self):
        """
        Return the first item in the data structure, without removing it
        :return: The first item in the data structure
        :rtype: object
        :raises: ValueError
        """
        # If no elements in data structure, return ValueError
        if self.size <= 0:
            raise ValueError('No elements in data structure to peak')

        # Else return the data from the first node
        else:
            return self.head.data

    def contains(self, element):
        """
        Determine if the element is in the data structure.
        :return: Whether the element is in the data structure.
        :rtype: bool
        """
        # If no elements in data structure, return False
        if self.size <= 0:
            return False
        # TODO Else check every element of the data structure sequentially, and return when we find a match
        print(self.head, type(self.head))
        cursor = self.head
        while cursor is not None:
            logging.info(f'Checking cursor: {cursor} for element: {element}')
            if cursor.data == element:
                return True
            cursor = cursor.next

        # TODO If we've gone through the whole data structure and not found a match, then item is not in data structure
        return False

class LinkedListNode(object):
    """
    Helper class, representing a node in the LinkedList
    """

    def __init__(self, data):
        self.data = data
        self.next = None


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 10 23:59:40 2020

@author: LAPPY jr
"""

# Polynomial Regression

# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
dataset = pd.read_csv('Position_Salaries.csv')
X=dataset.iloc[:,1:-1].values
Y=dataset.iloc[:,2].values

##taking care of missing data
#from sklearn.preprocessing import Imputer
#imputer=Imputer(missing_values='NaN',strategy='mean',axis=0)
#imputer=imputer.fit(X[:,1:3])
#X[:,1:3]=imputer.transform(X[:,1:4])

##Encoding Categorical data
#from sklearn.preprocessing import LabelEncoder as LE
#from sklearn.preprocessing import OneHotEncoder as OE
#labelencoder_x=LE()
#X[:,0]=labelencoder_x.fit_transform(X[:,0])
#onehotencoder=OE(categorical_features=[0])
#X=onehotencoder.fit_transform(X).toarray()

#makin the linear model
from sklearn.linear_model import LinearRegression as LR
linear_regressor=LR()
linear_regressor.fit(X,Y)

#makin the polynomial model
from sklearn.preprocessing import PolynomialFeatures as PF
poly_reg=PF(degree=8)
X_poly=poly_reg.fit_transform(X)
#polynomial model
linear_regressor2=LR()
linear_regressor2.fit(X_poly,Y)

#Visualizing the training set results using single linear regression
plt.scatter(X,Y,color='red')
plt.plot(X,linear_regressor.predict(X),color='black')
plt.title('Linear regressor model')
linear_regressor.predict(6.5.reshape(6.5,(-1,1)))
plt.scatter(linear_regressor.predict(6.5),b,color='green')

#Visualizing the training set results using polynomial regression
X_grid=np.arange(start=0,stop=10.1,step=0.001)
X_grid=X_grid.reshape(len(X_grid),1)
plt.scatter(X,Y,color='red')
plt.plot(X_grid,linear_regressor2.predict(poly_reg.fit_transform(X_grid)),color='black')
plt.title(' Polynomial Linear regressor model')
linear_regressor2.predict(6.5)
plt.scatter(linear_regressor2.predict(6.5),Y,color='green')


from tqdm import tqdm

from sdk.load_config import load_config_create_sessions
from sdk.color_print import c_print

from cloud_accounts import cld_sync
from account_groups import acc_sync
from resource_lists import rsc_sync
from user_roles import role_sync
from user_profiles import usr_sync
from ip_allow_lists import ip_sync
from compliance_standards import cmp_sync
from saved_searches import search_sync
from policies import plc_sync
from alert_rules import alr_sync
from anomaly_settings import ano_sync
from enterprise_settings import set_sync

def sync(tenant_sessions: list, modes: dict, logger):
    '''
    Accepts the enabled sync modes dictionary and a list of tenant_session objects.

    Depending on what sync modes are enabled, calls the sync functions while
    specifying the operations that are enabled.
    '''

    run_summary = {}

    mode_list = []
    for mode in modes.items():
        mode_list.append(mode[0])

    #ADDING AND UPDATING - Order based on dependencies.
    for mode in tqdm(mode_list, desc='SYNC ADD/UPDATE STATUS'):
        try:
            if 'cloud' == mode:
                added, updated, deleted, cld_sync_data = cld_sync.sync(tenant_sessions, modes['cloud'].get('add', True), modes['cloud'].get('update', True), False, logger)
                run_summary.update(added_cloud_accounts=added)
                run_summary.update(updated_cloud_accounts=updated)
                run_summary.update(deleted_cloud_accounts=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'account' == mode:
                added, updated, deleted, acc_sync_data = acc_sync.sync(tenant_sessions, modes['account'].get('add', True), modes['account'].get('update', True), False, logger)
                run_summary.update(added_account_groups=added)
                run_summary.update(updated_account_groups=updated)
                run_summary.update(deleted_account_groups=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'resource' == mode:
                added, updated, deleted, rsc_sync_data = rsc_sync.sync(tenant_sessions, modes['resource'].get('add', True), modes['resource'].get('update', True), False, logger)
                run_summary.update(added_resource_lists=added)
                run_summary.update(updated_resource_lists=updated)
                run_summary.update(deleted_resource_lists=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'role' == mode:
                added, updated, deleted, role_sync_data = role_sync.sync(tenant_sessions, modes['role'].get('add', True), modes['role'].get('update', True), False, logger)
                run_summary.update(added_roles=added)
                run_summary.update(updated_roles=updated)
                run_summary.update(deleted_roles=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'user' == mode:
                added, updated, deleted, usr_sync_data = usr_sync.sync(tenant_sessions, modes['user'].get('add', True), modes['user'].get('update', True), False, logger)
                run_summary.update(added_profiles=added)
                run_summary.update(updated_profiles=updated)
                run_summary.update(deleted_profiles=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'ip' == mode:
                added_networks, added_network_cidrs, added_logins, updated_network_cidrs, updated_logins, deleted_network_cidrs, deleted_logins, ip_sync_data = ip_sync.sync(tenant_sessions, modes['ip'].get('add', True), modes['ip'].get('update', True), False, logger)
                run_summary.update(added_networks=added_networks)
                run_summary.update(added_networks_cidrs=added_network_cidrs)
                run_summary.update(added_login_ips=added_logins)
                run_summary.update(updated_network_cidrs=updated_network_cidrs)
                run_summary.update(updated_login_ips=updated_logins)
                run_summary.update(deleted_network_cidrs=deleted_network_cidrs)
                run_summary.update(deleted_logins=deleted_logins)
        except Exception as error:
            logger.exception(error)

        try:
            if 'compliance' == mode:
                added_standards, added_requirements, added_sections, updated_standards, updated_requirements, updated_sections, deleted_standards, deleted_requirements, deleted_sections, cmp_sync_data = cmp_sync.sync(tenant_sessions, modes['compliance'].get('add', True), modes['compliance'].get('update', True), False, logger)
                run_summary.update(added_standards=added_standards)
                run_summary.update(added_requirements=added_requirements)
                run_summary.update(added_sections=added_sections)
                run_summary.update(updated_standards=updated_standards)
                run_summary.update(updated_requirements=updated_requirements)
                run_summary.update(updated_sections=updated_sections)
                run_summary.update(deleted_standards=deleted_standards)
                run_summary.update(deleted_requirements=deleted_requirements)
                run_summary.update(deleted_sections=deleted_sections)
        except Exception as error:
            logger.exception(error)

        try:
            if 'search' == mode:
                added_searches, deleted_searches, search_sync_data = search_sync.sync(tenant_sessions, modes['search'].get('add', True), False, logger)
                run_summary.update(added_searches=added_searches)
                run_summary.update(deleted_searches=deleted_searches)
        except Exception as error:
            logger.exception(error)

        try:
            if 'policy' == mode:
                added, updated, deleted, updated_default, plc_sync_data = plc_sync.sync(tenant_sessions, modes['policy'].get('add', True), modes['policy'].get('update', True), False, logger)
                run_summary.update(added_policies=added)
                run_summary.update(updated_policies=updated)
                run_summary.update(updated_default_policies=updated_default)
                run_summary.update(deleted_policies=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'alert' == mode:
                added, updated, deleted, alr_sync_data = alr_sync.sync(tenant_sessions, modes['alert'].get('add', True), modes['alert'].get('update', True), False, logger)
                run_summary.update(added_alerts=added)
                run_summary.update(updated_alerts=updated)
                run_summary.update(deleted_alerts=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'anomaly' == mode:
                added, updated, deleted, updated_network_settings, updated_ueba_settings, ano_sync_data = ano_sync.sync(tenant_sessions, modes['anomaly'].get('add', True), modes['anomaly'].get('update', True), False, logger)
                run_summary.update(added_anomaly=added)
                run_summary.update(updated_anomaly=updated)
                run_summary.update(deleted_anomaly=deleted)
                run_summary.update(updated_ueba_settings=updated_ueba_settings)
                run_summary.update(updated_network_settings=updated_network_settings)
        except Exception as error:
            logger.exception(error)

        try:
            if 'settings' == mode:
                updated = set_sync.sync(tenant_sessions, logger)
                run_summary.update(updated_enterprise_settings=updated)
        except Exception as error:
            logger.exception(error)

    #DELETEING - Order based on dependencies
    mode_list = mode_list[::-1]
    #Cloud accounts need to be deleted before account groups
    if 'cloud' in mode_list and 'account' in mode_list:
        mode_list[len(mode_list)-1], mode_list[len(mode_list)-2] = mode_list[len(mode_list)-2], mode_list[len(mode_list)-1]

    for mode in tqdm(mode_list, desc='SYNC DELETE STATUS'):
        try:
            if 'anomaly' == mode:
                if modes['anomaly'].get('delete', False):
                    added, updated, deleted, updated_network_settings, updated_ueba_settings, ano_sync_data = ano_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_anomaly=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'alert' == mode:
                if modes['alert'].get('delete', False):
                    added, updated, deleted, alr_sync_data = alr_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_alerts=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'policy' == mode:
                if modes['policy'].get('delete', False):
                    added, updated, deleted, updated_default, plc_sync_data = plc_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_policies=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'search' == mode:
                if modes['search'].get('delete', False):
                    added_searches, deleted_searches, search_sync_data = search_sync.sync(tenant_sessions, False, True, logger)
                    run_summary.update(deleted_searches=deleted_searches)
        except Exception as error:
            logger.exception(error)

        try:
            if 'compliance' == mode:
                if modes['compliance'].get('delete', False):
                    added_standards, added_requirements, added_sections, updated_standards, updated_requirements, updated_sections, deleted_standards, deleted_requirements, deleted_sections, cmp_sync_data = cmp_sync.sync(tenant_sessions, False, False, True, logger, cmp_sync_data)
                    run_summary.update(deleted_standards=deleted_standards)
                    run_summary.update(deleted_requirements=deleted_requirements)
                    run_summary.update(deleted_sections=deleted_sections)
        except Exception as error:
            logger.exception(error)

        try:
            if 'ip' == mode:
                if modes['ip'].get('delete', False):
                    added_networks, added_network_cidrs, added_logins, updated_network_cidrs, updated_logins, deleted_network_cidrs, deleted_logins, ip_sync_data = ip_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_network_cidrs=deleted_network_cidrs)
                    run_summary.update(deleted_logins=deleted_logins)
        except Exception as error:
            logger.exception(error)

        try:
            if 'user' == mode:
                if modes['user'].get('delete', False):
                    added, updated, deleted, usr_sync_data = usr_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_profiles=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'role' == mode:
                if modes['role'].get('delete', False):
                    added, updated, deleted, role_sync_data = role_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_roles=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'resource' == mode:
                if modes['resource'].get('delete', False):
                    added, updated, deleted, rsc_sync_data = rsc_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_resource_lists=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'cloud' == mode:
                if modes['cloud'].get('delete', False):
                    added, updated, deleted, cld_sync_data = cld_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_cloud_accounts=deleted)
        except Exception as error:
            logger.exception(error)

        try:
            if 'account' == mode:
                if modes['account'].get('delete', False):
                    added, updated, deleted, acc_sync_data = acc_sync.sync(tenant_sessions, False, False, True, logger)
                    run_summary.update(deleted_cloud_accounts=deleted)
        except Exception as error:
            logger.exception(error)

    c_print('************************', color='green')
    c_print('Finished syncing tenants', color='green')
    c_print('************************', color='green')
    print()

    clone_tenant_sessions = tenant_sessions[1:]
    for index in range(len(clone_tenant_sessions)):
        tenant = clone_tenant_sessions[index]

        added_cloud_accounts = run_summary.get('added_cloud_accounts')
        updated_cloud_accounts = run_summary.get('updated_cloud_accounts')
        deleted_cloud_accounts = run_summary.get('deleted_cloud_accounts')

        added_account_groups = run_summary.get('added_account_groups')
        updated_account_groups = run_summary.get('updated_account_groups')
        deleted_account_groups = run_summary.get('deleted_account_groups')

        added_resource_lists = run_summary.get('added_resource_lists')
        updated_resource_lists = run_summary.get('updated_resource_lists')
        deleted_resource_lists = run_summary.get('deleted_resource_lists')

        added_roles = run_summary.get('added_roles')
        updated_roles = run_summary.get('updated_roles')
        deleted_roles = run_summary.get('deleted_roles')

        added_profiles = run_summary.get('added_profiles')
        updated_profiles = run_summary.get('updated_profiles')
        deleted_profiles = run_summary.get('deleted_profiles')

        added_networks = run_summary.get('added_networks')
        added_networks_cidrs = run_summary.get('added_networks_cidrs')
        added_login_ips = run_summary.get('added_login_ips')
        updated_network_cidrs = run_summary.get('updated_network_cidrs')
        updated_login_ips = run_summary.get('updated_login_ips')
        deleted_network_cidrs = run_summary.get('deleted_network_cidrs')
        deleted_logins = run_summary.get('deleted_logins')

        added_standards = run_summary.get('added_standards')
        added_requirements = run_summary.get('added_requirements')
        added_sections = run_summary.get('added_sections')
        updated_standards = run_summary.get('updated_standards')
        updated_requirements = run_summary.get('updated_requirements')
        updated_sections = run_summary.get('updated_sections')
        deleted_standards = run_summary.get('deleted_standards')
        deleted_requirements = run_summary.get('deleted_requirements')
        deleted_sections = run_summary.get('deleted_sections')

        added_searches = run_summary.get('added_searches')
        deleted_searches = run_summary.get('deleted_searches')

        added_policies = run_summary.get('added_policies')
        updated_policies = run_summary.get('updated_policies')
        updated_default_policies = run_summary.get('updated_default_policies')
        deleted_policies = run_summary.get('deleted_policies')

        added_alerts = run_summary.get('added_alerts')
        updated_alerts = run_summary.get('updated_alerts')
        deleted_alerts = run_summary.get('deleted_alerts')

        added_anomaly = run_summary.get('added_anomaly')
        updated_anomaly = run_summary.get('updated_anomaly')
        deleted_anomaly = run_summary.get('deleted_anomaly')
        updated_network_settings = run_summary.get('updated_network_settings')
        updated_ueba_settings = run_summary.get('updated_ueba_settings')

        updated_enterprise_settings = run_summary.get('updated_enterprise_settings')

        logger.info(f'RUN SUMMARY FOR TENANT {tenant.tenant}')

        logger.info(f'Added {count(added_cloud_accounts, index)} Cloud Accounts')
        logger.info(f'Updated {count(updated_cloud_accounts, index)} Cloud Accounts')
        logger.info(f'Deleted {count(deleted_cloud_accounts, index)} Cloud Accounts')

        logger.info(f'Added {count(added_account_groups, index)} Cloud Account Groups')
        logger.info(f'Updated {count(updated_account_groups, index)} Cloud Acccount Groups')
        logger.info(f'Deleted {count(deleted_account_groups, index)} Cloud Account Groups')

        logger.info(f'Added {count(added_resource_lists, index)} Resource Lists')
        logger.info(f'Updated {count(updated_resource_lists, index)} Resource Lists')
        logger.info(f'Deleted {count(deleted_resource_lists, index)} Resource Lists')

        logger.info(f'Added {count(added_roles, index)} User Roles')
        logger.info(f'Updated {count(updated_roles, index)} User Roles')
        logger.info(f'Deleted {count(deleted_roles, index)} User Roles')

        logger.info(f'Added {count(added_profiles, index)} User Profiles')
        logger.info(f'Updated {count(updated_profiles, index)} User Profiles')
        logger.info(f'Deleted {count(deleted_profiles, index)} User Profiles')

        logger.info(f'Added {count(added_networks, index)} Networks')
        logger.info(f'Added {count(added_networks_cidrs, index)} Network CIDRs')
        logger.info(f'Added {count(added_login_ips, index)} Login IPs')
        logger.info(f'Updated {count(updated_network_cidrs, index)} Network CIDRs')
        logger.info(f'Updated {count(updated_login_ips, index)} Login IPs')
        logger.info(f'Deleted {count(deleted_network_cidrs, index)} Network CIDRs')
        logger.info(f'Deleted {count(deleted_logins, index)} Login IPs')

        logger.info(f'Added {count(added_standards, index)} Compliance Standards')
        logger.info(f'Added {count(added_requirements, index)} Compliance Requirements')
        logger.info(f'Added {count(added_sections, index)} Compliance Sections')
        logger.info(f'Updated {count(updated_standards, index)} Compliance Standards')
        logger.info(f'Updated {count(updated_requirements, index)} Compliance Requirements')
        logger.info(f'Updated {count(updated_sections, index)} Compliance Sections')
        logger.info(f'Deleted {count(deleted_standards, index)} Compliance Standards')
        logger.info(f'Deleted {count(deleted_requirements, index)} Compliance Requirements')
        logger.info(f'Deleted {count(deleted_sections, index)} Compliance Sections')

        logger.info(f'Added {count(added_searches, index)} Saved Searches')
        logger.info(f'Deleted {count(deleted_searches, index)} Saved Searches')

        logger.info(f'Added {count(added_policies, index)} Custom Policies')
        logger.info(f'Updated {count(updated_policies, index)} Custom Policies')
        logger.info(f'Updated {count(updated_default_policies, index)} Default Policies')
        logger.info(f'Deleted {count(deleted_policies, index)} Custom Policies')

        logger.info(f'Added {count(added_alerts, index)} Alert Rules')
        logger.info(f'Updated {count(updated_alerts, index)} Alert Rules')
        logger.info(f'Deleted {count(deleted_alerts, index)} Alert Rules')

        logger.info(f'Updated {count(updated_network_settings, index)} Anomaly Network Settings')
        logger.info(f'Updated {count(updated_ueba_settings, index)} Anomaly UEBA Settings')
        logger.info(f'Added {count(added_anomaly, index)} Anomaly Lists')
        logger.info(f'Updated {count(updated_anomaly, index)} Anomaly Lists')
        logger.info(f'Deleted {count(deleted_anomaly, index)} Anomaly Lists')

        updated_enter_set = count(updated_enterprise_settings, index)
        if updated_enter_set == 0:
            updated_enter_set = False
        logger.info(f'Updated enterprise settings T/F: {updated_enter_set}')

#Helper function for Run Summary
def count(count_list: list, index: int):
    try:
        val = count_list[index]
        return val
    except:
        return 0

if __name__ == '__main__':
    sync()

# DELETION ORDER
# Policies - Saved Search - Users - Roles - Resource Lists - Cloud Accounts - Account Groups
# Cant deleteete an account group that is still linked to a cloud account so cloud accounts must be synced/updated first.


"""
Each ListNode holds a reference to its previous node
as well as its next node in the List.
"""
class ListNode:
    def __init__(self, value, prev=None, next=None):
        self.next = next
        self.value = value
        self.prev = prev

"""
Our doubly-linked list class. It holds references to
the list's head and tail nodes.
"""
class DoublyLinkedList:
    def __init__(self, node=None):
        self.head = node
        self.tail = node
        self.length = 1 if node is not None else 0

    def __len__(self):
        return self.length

    """
    Wraps the given value in a ListNode and inserts it
    as the new head of the list. Don't forget to handle
    the old head node's previous pointer accordingly.
    """
    def add_to_head(self, value):
        if self.__len__() == 0:
            self.head = ListNode(value)
            self.tail = self.head
            self.length += 1
        elif self.__len__() == 1:
            self.head = ListNode(value, prev=self.tail)
            self.tail.next = self.head
            self.length += 1
        else:
            new_head = ListNode(value, prev=self.head)
            self.head.next = new_head
            self.head = new_head
            self.length += 1

    """
    Removes the List's current head node, making the
    current head's next node the new head of the List.
    Returns the value of the removed Node.
    """
    def remove_from_head(self):
        if self.__len__() == 0:
            return None
        elif self.__len__() == 1:
            head_value = self.head.value
            self.head = None
            self.tail = None
            self.length -= 1
            return head_value
        else:
            head_value = self.head.value
            self.head = self.head.prev
            self.head.next = None
            self.length -= 1
            return head_value

    """
    Wraps the given value in a ListNode and inserts it
    as the new tail of the list. Don't forget to handle
    the old tail node's next pointer accordingly.
    """
    def add_to_tail(self, value):
        if self.__len__() == 0:
            self.head = ListNode(value, prev=None, next=None)
            self.tail = self.head
            self.length += 1
        elif self.__len__() == 1:
            self.tail = ListNode(value, prev=None, next=self.head)
            self.head.prev = self.tail
            self.length += 1
        else:
            new_tail = ListNode(value, prev=None, next=self.tail)
            self.tail.prev = new_tail
            self.tail = new_tail
            self.length += 1

    """
    Removes the List's current tail node, making the
    current tail's previous node the new tail of the List.
    Returns the value of the removed Node.
    """
    def remove_from_tail(self):
        if self.__len__() == 0:
            return None
        elif self.__len__() == 1:
            remove_value = self.tail.value
            self.head = None
            self.tail = None
            self.length -= 1
            return remove_value
        else:
            remove_value = self.tail.value
            self.tail = self.tail.next
            self.tail.prev = None
            self.length -= 1
            return remove_value

    """
    Removes the input node from its current spot in the
    List and inserts it as the new head node of the List.
    """

    def move_to_front(self, node):
        if self.delete(node) != None:
            node_value = node.value
            self.add_to_head(node_value)

    """
    Removes the input node from its current spot in the
    List and inserts it as the new tail node of the List.
    """

    def move_to_end(self, node):
        if self.delete(node) != None:
            node_value = node.value
            self.add_to_tail(node_value)

    """
    Deletes the input node from the List, preserving the
    order of the other elements of the List.
    """

    def delete(self, node):
        if node == None:
            return None
        if self.__len__() == 0:
            return None
        elif self.__len__() == 1:
            self.head = None
            self.tail = None
            self.length -= 1
        else:
            curr_node = self.tail
            while curr_node != None:
                if curr_node.value == node.value and curr_node is self.tail:
                    self.tail = self.tail.next
                    self.tail.prev = None
                    self.length -= 1
                    return f'Node is deleted'
                elif curr_node.value == node.value and curr_node is self.head:
                    self.head = self.head.prev
                    self.head.next = None
                    self.length -= 1
                    return f'Node is deleted'
                elif curr_node.value == node.value:
                    curr_node.next.prev = curr_node.prev
                    curr_node.prev.next = curr_node.next
                    self.length -= 1
                    return f'Node is deleted'
                curr_node = curr_node.next

    """
    Finds and returns the maximum value of all the nodes
    in the List.
    """

    def get_max(self):
        if self.__len__() == 0:
            return None
        else:
            values_list = []
            curr_node = self.tail
            while curr_node is not None:
                values_list.append(curr_node.value)
                curr_node = curr_node.next
            return max(values_list)


import connexion
from src.state import State
from datetime import datetime
from flask import session
from sqlalchemy import func
from sqlalchemy import desc
import math
import six

from src.api.models.appointment_data import AppointmentData  # noqa: E501
from src.api.models.clinic import Clinic  # noqa: E501
from src.api.models.clinic_filter import ClinicFilter  # noqa: E501
from src.api.models.not_found_error_response import NotFoundErrorResponse  # noqa: E501
from src.api.models.response import Response  # noqa: E501
from src.api.models.server_error_response import ServerErrorResponse  # noqa: E501
from src.api.models.unauthorized_error_response import UnauthorizedErrorResponse  # noqa: E501
from src.api import util
from src.api.decorators.auth import requires_auth, requires_no_auth

from src.db.models.clinic import Clinic as DBClinic
from src.db.models.user import User as DBUser
from src.db.models.appointment import Appointment as DBAppointment
from src.db.models.appointment import Status
from src.db.models.appointment_detail import AppointmentDetail
from src.db.models.schedule_appointment import ScheduleAppointment
from src.db.models.schedule import Schedule
from src.db.models.appointment_detail_ids import AppointmentDetailIds
from src.db.models.clinic_staff import ClinicStaff
from src.db.models.staff import Staff
from src.db.models.doctor import Doctor
from src.db.models.receptionist import Receptionist
from src.db.models.notification import Notification
from src.db.models.symptom import Symptom

@requires_auth()
def add_clinic_staff(id, email, filter):  # noqa: E501
    """Add clinic staff

    Add staff with email from clinic ID with staff filter. Can be set to \"doctor\", \"receptionist\" # noqa: E501

    :param id: Clinic ID
    :type id: int
    :param email: Staff Email
    :type email: str
    :param filter: filter for staff type
    :type filter: str

    :rtype: Response
    """
    # Check if clinic is verified
    clinic = State.db.session.query(DBClinic).filter_by(id=id).one_or_none()
    if clinic is None or clinic.is_verified is False:
        return ServerErrorResponse(message="That clinic does not exist.")
    # Adding doctors
    if filter == "doctor":
        doctor_staff = State.db.session.query(Staff).join(Doctor).join(DBUser).filter(
            DBUser.email == email,
            Staff.user_id == DBUser.id,
            Doctor.staff_id == Staff.id,
            Doctor.is_verified == True,
            Doctor.date_deleted == None
        ).one_or_none()
        if doctor_staff is None:
            return ServerErrorResponse(message="Doctor does not exist.")
        # Check if already added
        doc_clinic_staff = State.db.session.query(ClinicStaff).filter_by(
            clinic_id=id,
            staff_id=doctor_staff.id,
            date_deleted=None
        ).one_or_none()
        if doc_clinic_staff is not None:
            return ServerErrorResponse(message="Doctor was already added to that clinic")
        else:
            State.db.session.add(ClinicStaff(clinic_id=id, staff_id=doctor_staff.id))
            State.db.session.commit()
            return Response(data="Doctor with email " + str(email) + " added to clinic " + str(id))
    # Adding receptionist
    if filter == "receptionist":
        receptionist_staff = State.db.session.query(Staff).join(Receptionist).join(DBUser).filter(
            DBUser.email == email,
            Staff.user_id == DBUser.id,
            Receptionist.staff_id == Staff.id,
            Receptionist.date_deleted == None
        ).one_or_none()
        if receptionist_staff is None:
            return ServerErrorResponse(message="Receptionist does not exist.")
        # Check if already added
        rec_clinic_staff = State.db.session.query(ClinicStaff).filter_by(
            clinic_id=id,
            staff_id=receptionist_staff.id,
            date_deleted=None
        ).one_or_none()
        if rec_clinic_staff is not None:
            return ServerErrorResponse(message="Receptionist was already added to that clinic")
        else:
            State.db.session.add(ClinicStaff(clinic_id=id, staff_id=receptionist_staff.id))
            State.db.session.commit()
            return Response(data="Receptionist with email " + str(email) + " added to clinic " + str(id))

@requires_auth()
def create_clinic(clinic=None):  # noqa: E501
    """Add a new clinic

    Adds a new clinic into the db and returns the clinic id # noqa: E501

    :param clinic: Clinic object
    :type clinic: dict | bytes

    :rtype: Response
    """
    if connexion.request.is_json:
        clinic = Clinic.from_dict(connexion.request.get_json())  # noqa: E501

    new_clinic = DBClinic(
        name=clinic.name,
        address=clinic.address,
        location=str(clinic.city) + ", " + str(clinic.province),
        phone_number=clinic.phone_number,
        fax_number=clinic.fax,
        email=clinic.email,
        owner_id=clinic.owner_id,
        latitude=clinic.latitude,
        longitude=clinic.longitude,
        hours_of_operation=clinic.hours_of_operation,
        place_id=clinic.place_id,
        postal_code=clinic.postal_code,
        summary=clinic.summary,
        description=clinic.description,
        map_url=clinic.map_url,
        website=clinic.website
    )

    State.db.session.add(new_clinic)
    State.db.session.commit()

    # If current user is a verified doctor, add as verified doctor to clinic
    doctor_staff = State.db.session.query(Staff).join(Doctor).filter(
        Staff.user_id == clinic.owner_id,
        Doctor.staff_id == Staff.id,
        Doctor.is_verified == True,
        Doctor.date_deleted == None
    ).one_or_none()
    if doctor_staff is not None:
        # Check if already added
        doc_clinic_staff = State.db.session.query(ClinicStaff).filter_by(clinic_id=new_clinic.id, staff_id=doctor_staff.id).one_or_none()
        if doc_clinic_staff is None:
            State.db.session.add(ClinicStaff(clinic_id=new_clinic.id, staff_id=doctor_staff.id))
            State.db.session.commit()

    return Response(data=new_clinic.serialize())

@requires_auth()
def delete_clinic(id):  # noqa: E501
    """Delete clinic data

    Delete clinic from db # noqa: E501

    :param id: Clinic ID
    :type id: int

    :rtype: Response
    """
    # Make sure there are no appointments under clinic before deleting
    appointments = State.db.session.query(DBAppointment).filter_by(clinic_id=id).all()
    if len(appointments) > 0:
        return ServerErrorResponse(message="There are still appointments in that clinic.")
    deleted_clinic = State.db.session.query(DBClinic).filter_by(id=id).one_or_none()
    if not deleted_clinic:
        return ServerErrorResponse(message="Clinic does not exist.")
    if deleted_clinic.date_deleted is not None:
        return ServerErrorResponse(message="That clinic has already been deleted.")
    deleted_clinic.date_deleted = datetime.utcnow()
    deleted_clinic.date_updated = datetime.utcnow()
    State.db.session.commit()
    return Response(data=deleted_clinic.serialize())

@requires_auth()
def delete_clinic_staff(id, uid, filter):  # noqa: E501
    """Delete clinic staff

    Removestaff with user id of staff to clinic ID with staff filter. Can be set to \"doctor\", \"receptionist\" # noqa: E501

    :param id: Clinic ID
    :type id: int
    :param uid: Staff ID
    :type uid: int
    :param filter: filter for staff type
    :type filter: str

    :rtype: Response
    """
    # Removing doctors
    if filter == "doctor":
        # Make sure doctor does not have any appointments at this clinic, to reduce complete blow up of app :)
        doc_appointment = State.db.session.query(DBAppointment).join(AppointmentDetail).join(
            AppointmentDetailIds).filter(
            AppointmentDetailIds.doctor_id == uid,
            AppointmentDetail.detail_id == AppointmentDetailIds.id,
            AppointmentDetail.appointment_id == DBAppointment.id,
            DBAppointment.clinic_id == id
        ).all()
        if len(doc_appointment) > 0:
            return ServerErrorResponse("That doctor still has appointments at that clinic.")
        doctor_staff = State.db.session.query(Staff).join(Doctor).filter(
            Staff.user_id == uid,
            Doctor.staff_id == Staff.id
        ).one_or_none()
        if doctor_staff is None:
            return ServerErrorResponse(message="Doctor does not exist.")
        # Check if already added
        doc_clinic_staff = State.db.session.query(ClinicStaff).filter_by(clinic_id=id, staff_id=doctor_staff.id, date_deleted=None).one_or_none()
        if doc_clinic_staff is None:
            return ServerErrorResponse(message="Doctor wasn't appart of that clinic")
        else:
            doc_clinic_staff.date_deleted = datetime.utcnow()
            doc_clinic_staff.date_updated = datetime.utcnow()
            State.db.session.commit()
            return Response(data="Doctor with uid " + str(uid) + " removed from clinic " + str(id))
    # Removing receptionist
    if filter == "receptionist":
        receptionist_staff = State.db.session.query(Staff).join(Receptionist).filter(
            Staff.user_id == uid,
            Receptionist.staff_id == Staff.id
        ).one_or_none()
        if receptionist_staff is None:
            return ServerErrorResponse(message="Receptionist does not exist.")
        # Check if already added
        rec_clinic_staff = State.db.session.query(ClinicStaff).filter_by(clinic_id=id, staff_id=receptionist_staff.id, date_deleted=None).one_or_none()
        if rec_clinic_staff is None:
            return ServerErrorResponse(message="Receptionist was never added to that clinic")
        else:
            rec_clinic_staff.date_deleted = datetime.utcnow()
            rec_clinic_staff.date_updated = datetime.utcnow()
            State.db.session.commit()
            return Response(data="Receptionist with uid " + str(uid) + " removed from clinic " + str(id))

@requires_auth()
def get_clinic(id):  # noqa: E501
    """Get clinic data

    Get clinic information from provided ID # noqa: E501

    :param id: Clinic ID
    :type id: int

    :rtype: Response
    """
    clinic = State.db.session.query(DBClinic).filter_by(id=id).one_or_none()
    if not clinic or clinic.is_verified is False:
        return ServerErrorResponse(message="Clinic does not exist.")
    if clinic.date_deleted is not None:
        return ServerErrorResponse(message="The clinic you are searching has been deleted.")
    return Response(data=clinic.serialize())

@requires_auth()
def get_clinic_appointment_length(id, medical_data=None):  # noqa: E501
    """Get clinic appointment estimated length

    Get clinic appointment estimated length from provided ID, provided the appointment data (symptoms, doctors) and give the user id(s) in the extra field of hte appointment data model # noqa: E501

    :param id: Clinic ID
    :type id: int
    :param medical_data: appointment medical data
    :type medical_data: dict | bytes

    :rtype: Response
    """
    if connexion.request.is_json:
        medical_data = AppointmentData.from_dict(connexion.request.get_json())  # noqa: E501
    # number of symptoms
    symptom_num = medical_data.symptoms.__len__()
    # max amount of appointments to consider
    appointment_max = 20
    # Calculation weights
    clinic_weight = 0.5
    doctor_weight = 0.3
    patient_weight = 0.2
    # Averages
    doctor_average = 0
    patient_average = 0
    clinic_average = 0

    if symptom_num == 0:
        return Response(data=10)

    # Get average time for N symptoms from clinic using moving average
    clinic_appointments = State.db.session.query(DBAppointment).filter(
        DBAppointment.clinic_id == id,
        DBAppointment.status == Status.completed
    ).group_by(DBAppointment.id).order_by(desc(DBAppointment.start_time)).limit(appointment_max).all()
    # Get the average
    clinic_app_list = []
    count = 0
    for app in clinic_appointments:
        symptoms = State.db.session.query(AppointmentDetailIds).join(AppointmentDetail).filter(
            AppointmentDetail.appointment_id == app.id,
            AppointmentDetail.detail_id == AppointmentDetailIds.id,
            AppointmentDetailIds.symptom_id != None
        ).all()
        if symptoms.__len__() != 0:
            clinic_app_list.append(((app.actual_end_time - app.actual_start_time).seconds / 60) / symptoms.__len__())
        count += 1
        if count == appointment_max:
            break
    if clinic_app_list.__len__() != 0:
        clinic_average = (sum(clinic_app_list) / clinic_app_list.__len__()) * symptom_num

    # Get average time for N symptoms from each doctor using moving average
    doc_id_list = []
    for doc in medical_data.doctor:
        doc_id_list.append(doc['id'])
    if doc_id_list is None:
        doc_id_list.append(0)
    doctor_appointments = State.db.session.query(DBAppointment).join(AppointmentDetail).join(
            AppointmentDetailIds).filter(
            AppointmentDetailIds.doctor_id == doc_id_list[0],
            AppointmentDetail.detail_id == AppointmentDetailIds.id,
            AppointmentDetail.appointment_id == DBAppointment.id,
            DBAppointment.date_deleted == None,
            DBAppointment.status == Status.completed
        ).order_by(desc(DBAppointment.start_time)).limit(appointment_max).all()
    # Get the average
    doc_app_list = []
    count = 0
    for app in doctor_appointments:
        app_symptoms = State.db.session.query(AppointmentDetailIds).join(AppointmentDetail).filter(
            AppointmentDetail.detail_id == AppointmentDetailIds.id,
            AppointmentDetail.appointment_id == app.id,
            AppointmentDetailIds.date_deleted == None,
            AppointmentDetailIds.symptom_id != None
        ).all()
        if app_symptoms.__len__() != 0:
            doc_app_list.append(((app.actual_end_time - app.actual_start_time).seconds / 60) / app_symptoms.__len__())
        count += 1
        if count == appointment_max:
            break
    if doc_app_list.__len__() != 0:
        doctor_average = (sum(doc_app_list) / doc_app_list.__len__()) * symptom_num

    # Get average time for N symptoms from patient using moving average
    user_id = medical_data.extra["user_id"]
    if user_id is None:
        user_id = 0
    patient_appointments = State.db.session.query(DBAppointment).join(ScheduleAppointment).join(Schedule).filter(
        DBAppointment.status == Status.completed,
        ScheduleAppointment.appointment_id == DBAppointment.id,
        ScheduleAppointment.schedule_id == Schedule.id,
        Schedule.user_id == user_id
    ).order_by(desc(DBAppointment.start_time)).limit(appointment_max).all()
    # Get the average
    patient_app_list = []
    count = 0
    for app in patient_appointments:
        symptoms = State.db.session.query(AppointmentDetailIds).join(AppointmentDetail).filter(
            AppointmentDetail.appointment_id == app.id,
            AppointmentDetail.detail_id == AppointmentDetailIds.id,
            AppointmentDetailIds.symptom_id != None
        ).all()
        if symptoms.__len__() != 0:
            patient_app_list.append(((app.actual_end_time - app.actual_start_time).seconds / 60) / symptoms.__len__())
        count += 1
        if count == appointment_max:
            break
    if patient_app_list.__len__() != 0:
        patient_average = (sum(patient_app_list) / patient_app_list.__len__()) * symptom_num

    # Check to make sure there were actual values for each, of not adjust weights
    appointment_length = 0
    if clinic_average == 0 and doctor_average == 0 and patient_average == 0:
        # If there are no values, then multiply symptoms by 3 min each
        appointment_length = (3 * medical_data.symptoms.__len__()) + 10
    elif clinic_average == 0 and doctor_average == 0:
        appointment_length = patient_average
    elif clinic_average == 0 and patient_average == 0:
        appointment_length = doctor_average
    elif doctor_average == 0 and patient_average == 0:
        appointment_length = clinic_average
    elif doctor_average == 0:
        appointment_length = (clinic_average * (clinic_weight + (doctor_weight / 2))) \
                             + (patient_average * (patient_weight + (doctor_weight / 2)))
    elif clinic_average == 0:
        appointment_length = (doctor_average * (doctor_weight + (clinic_weight / 2))) \
                             + (patient_average * (patient_weight + (clinic_weight / 2)))
    elif patient_average == 0:
        appointment_length = (clinic_average * (clinic_weight + (patient_weight / 2))) \
                             + (doctor_average * (doctor_weight + (patient_weight / 2)))
    else:  # If all data is available
        appointment_length = (clinic_average * clinic_weight) + (doctor_average * doctor_weight) \
                             + (patient_average * patient_weight)
    # round length up to nearest integer value
    appointment_length = math.ceil(appointment_length / 5) * 5
    return Response(data=appointment_length)

@requires_auth()
def get_clinic_appointments(id):  # noqa: E501
    """Get clinic appointments

    Get clinic appointments from provided ID, along with the patient and doctors # noqa: E501

    :param id: Clinic ID
    :type id: int

    :rtype: Response
    """

    # Check if clinic is verified
    clinic = State.db.session.query(DBClinic).filter_by(id=id).one_or_none()
    if clinic is None or clinic.is_verified is False:
        return ServerErrorResponse(message="That clinic does not exist.")

    appointment_list = State.db.session.query(DBAppointment).filter_by(clinic_id=id, date_deleted=None).all()
    if not appointment_list:
        return Response(data=None)

    return_list = []
    for appointment in appointment_list:
        return_list.append(appointment.serialize())

    return Response(data={
        "clinic_appointments": return_list,
    })

@requires_auth()
def get_clinic_staff(id, filter=None):  # noqa: E501
    """Get clinic staff

    Get user ids of staff from clinic ID with an optional staff filter. Can be set to \"doctor\", \"receptionist\" # noqa: E501

    :param id: Clinic ID
    :type id: int
    :param filter: filter for clinic type, if null ignore filter
    :type filter: str

    :rtype: Response
    """
    # Check if clinic is verified
    clinic = State.db.session.query(DBClinic).filter_by(id=id).one_or_none()
    if clinic is None or clinic.is_verified is False:
        return ServerErrorResponse(message="That clinic does not exist.")
    if filter == "doctor":
        doctor_list = State.db.session.query(DBUser).join(Staff).join(ClinicStaff).join(Doctor).filter(
            ClinicStaff.clinic_id == id,
            ClinicStaff.date_deleted == None,
            Staff.user_id == DBUser.id,
            ClinicStaff.staff_id == Staff.id,
            Doctor.staff_id == Staff.id,
            Doctor.is_verified == True
        ).all()
        if not doctor_list:
            return ServerErrorResponse(message="There are no doctors for that clinic.")
        return_list = []
        for doctor in doctor_list:
            return_list.append({
                "id": doctor.id,
                "first_name": doctor.first_name,
                "last_name": doctor.last_name
            })

        return Response(data={"clinic_doctors": return_list})

    if filter == "receptionist":
        receptionist_list = State.db.session.query(DBUser).join(Staff).join(ClinicStaff).join(Receptionist).filter(
            ClinicStaff.clinic_id == id,
            ClinicStaff.date_deleted == None,
            Staff.user_id == DBUser.id,
            ClinicStaff.staff_id == Staff.id,
            Receptionist.staff_id == Staff.id
        ).all()
        if not receptionist_list:
            return ServerErrorResponse(message="There are no receptionists for that clinic.")
        return_list = []
        for receptionist in receptionist_list:
            return_list.append({
                "id": receptionist.id,
                "first_name": receptionist.first_name,
                "last_name": receptionist.last_name
            })

        return Response(data={"clinic_receptionists": return_list})

    if filter is None:
        staff_list = State.db.session.query(DBUser).join(Staff).join(ClinicStaff).filter(
            ClinicStaff.clinic_id == id,
            ClinicStaff.date_deleted == None,
            Staff.user_id == DBUser.id,
            ClinicStaff.staff_id == Staff.id
        ).all()
        if not staff_list:
            return ServerErrorResponse(message="There are no staff for that clinic.")
        return_list = []
        for staff in staff_list:
            return_list.append({
                "id": staff.id,
                "first_name": staff.first_name,
                "last_name": staff.last_name
            })

        return Response(data={"clinic_staff": return_list})

@requires_auth()
def get_clinics():  # noqa: E501
    """Get All Clinics

    Get a list of all current clinics in the DB # noqa: E501

    :rtype: Response
    """
    if connexion.request.is_json:
        clinic_filter = ClinicFilter.from_dict(connexion.request.get_json())  # noqa: E501
    clinic_list = State.db.session.query(DBClinic).filter_by(date_deleted=None, is_verified=True).all()
    if not clinic_list:
        return ServerErrorResponse(message="No clinics exist.")

    return_list = [clinic.serialize() for clinic in clinic_list]

    return Response(data={"clinics": return_list})

@requires_auth()
def get_clinics_unverified():  # noqa: E501
    """Get Unverified Clinics

    Get all unverified clinics # noqa: E501

    :rtype: Response
    """
    # Get current user and check if an admin
    is_admin = session['profile']['is_admin']
    if is_admin is False:
        return ServerErrorResponse(message="You are not an admin.")
    # Pull all unverified doctors
    unverified_clinics = State.db.session.query(DBUser, DBClinic).filter(
        DBClinic.date_deleted == None,
        DBClinic.is_verified == False,
        DBUser.id == DBClinic.owner_id
    ).all()
    # Create the JSON object from data
    unverified_list = []
    for clinic in unverified_clinics:
        unverified_list.append({
            "clinic": clinic.Clinic.serialize(),
            "owner": clinic.User.serialize()
        })
    # Return list
    return Response(data=unverified_list)

@requires_auth()
def update_clinic(clinic=None):  # noqa: E501
    """Update clinic data

    Update the clinic information in the db # noqa: E501

    :param clinic: Clinic object
    :type clinic: dict | bytes

    :rtype: Response
    """
    if connexion.request.is_json:
        clinic = Clinic.from_dict(connexion.request.get_json())  # noqa: E501

    updated_clinic = State.db.session.query(DBClinic).filter_by(id=clinic.id).one_or_none()
    is_admin = session['profile']['is_admin']

    if updated_clinic.is_verified is False and is_admin is False:
        return ServerErrorResponse(message="That clinic is not verified.")

    if not updated_clinic:
        return ServerErrorResponse(message="That clinic does not exist.")

    if clinic.name is not None:
        updated_clinic.name = clinic.name
    if clinic.address is not None:
        updated_clinic.address = clinic.address
    if clinic.phone_number is not None:
        updated_clinic.phone_number = clinic.phone_number
    if clinic.fax is not None:
        updated_clinic.fax = clinic.fax
    if clinic.city is not None and clinic.province is not None:
        updated_clinic.location = clinic.city + ", " + clinic.province
    if clinic.email is not None:
        updated_clinic.email = clinic.email
    if clinic.latitude is not None:
        updated_clinic.latitude = clinic.latitude
    if clinic.longitude is not None:
        updated_clinic.longitude = clinic.longitude
    if clinic.place_id is not None:
        updated_clinic.place_id = clinic.place_id
    if clinic.postal_code is not None:
        updated_clinic.postal_code = clinic.postal_code
    if clinic.summary is not None:
        updated_clinic.summary = clinic.summary
    if clinic.description is not None:
        updated_clinic.description = clinic.description
    if clinic.website is not None:
        updated_clinic.website = clinic.website
    if clinic.map_url is not None:
        updated_clinic.map_url = clinic.map_url

    updated_clinic.date_updated = datetime.utcnow()

    State.db.session.commit()

    return Response(data=updated_clinic.serialize())

@requires_auth()
def verify_clinic(id):  # noqa: E501
    """Verify clinic

    Verify the clinic with the given id # noqa: E501

    :param id: Clinic ID
    :type id: int

    :rtype: Response
    """
    # Check if user is admin
    is_admin = session['profile']['is_admin']
    if is_admin is False:
        return ServerErrorResponse(message="You do not have admin privileges.")
    clinic = State.db.session.query(DBClinic).filter(DBClinic.id == id, DBClinic.date_deleted == None).one_or_none()
    if clinic is None:
        return ServerErrorResponse(message="That clinic does not exist")
    else:
        clinic.is_verified = True
        State.db.session.commit()
        # Create a notification to user
        notification = Notification(
            user_id=clinic.owner_id,
            title="Clinic has been verified!",
            summary="Your clinic " + str(clinic.name) + " has been verified."
        )
        State.db.session.add(notification)
        State.db.session.commit()
        return Response(data=clinic.serialize())


__author__ = 'Bohdan Mushkevych'

from six import string_types
from odm.document import BaseDocument
from odm.fields import StringField, ListField

TREE_NAME = 'tree_name'
DEPENDENT_ON = 'dependent_on'
ENCLOSED_PROCESSES = 'enclosed_processes'
MX_PAGE = 'mx_page'
MX_NAME = 'mx_name'

class TimetableTreeEntry(BaseDocument):
    """ Non-persistent model. Class presents single process tree (an atomic entry for the Timetable) """

    tree_name = StringField(TREE_NAME)
    dependent_on = ListField(DEPENDENT_ON)
    enclosed_processes = ListField(ENCLOSED_PROCESSES)
    mx_name = StringField(MX_NAME)
    mx_page = StringField(MX_PAGE)

    @BaseDocument.key.getter
    def key(self):
        return self.tree_name

    @key.setter
    def key(self, value):
        self.tree_name = value

def timetable_tree_entry(tree_name,
                         enclosed_processes,
                         dependent_on=None,
                         mx_name=None,
                         mx_page=None):
    """ creates timetable context entry """
    assert enclosed_processes is not None and not isinstance(enclosed_processes, string_types)
    assert dependent_on is not None and not isinstance(dependent_on, string_types)

    timetable_entry = TimetableTreeEntry(tree_name=tree_name,
                                         enclosed_processes=enclosed_processes,
                                         dependent_on=dependent_on,
                                         mx_name=mx_name,
                                         mx_page=mx_page)
    return timetable_entry


from flask import Blueprint, session, request, redirect, url_for, render_template

utils_bp = Blueprint('index', __name__, url_prefix='/',template_folder='views')

@utils_bp.route('/')
def index():
    return redirect('users/list')

@utils_bp.before_request
def require_login():
    allowed_routes = ['users.login', 'users.signup','index.index','blogs.blog']
    print(request.endpoint)
    if request.endpoint not in allowed_routes and 'user_id' not in session:
        return redirect('users/login')


import api
import urllib.request
import urllib.parse
import json

def getWeather(location):
    # yql's gross. perhaps i can find something cleaner. wunderground wasn't bad
    # duplicated from
    # https://github.com/hashbang/irc-bot/blob/master/plugins/weather.lua
    location = location.replace("'", "\\'")

    query = "select * from weather.forecast where woeid in (" +\
            "select woeid from geo.places(1) where text='" +\
            location +\
            "') and u='f'"

    url = "http://query.yahooapis.com/v1/public/yql?q=" +\
        urllib.parse.quote(query) + "&format=json"

    resp = urllib.request.urlopen(url).read().decode('utf-8')
    result = json.loads(resp)['query']
    item = result['results']['channel']['item']

    temp = int(item['condition']['temp'])

    # Build the output, add some color to it.
    out = [
        item['title'].replace("for ", "for {yellow}").replace(" at ", "{} at "),
        "{blue}" + item['condition']['text'] + "{}",
        "{}°F".format(temp),
        "({} °C)".format((temp - 32)*5//9)]

    return " ".join(out)

@api.onCommand("w")
def doWeather(who, msg, where):
    res = getWeather(msg)

    api.privmsg(where, res)


# All URLs involving the logging in of a user via their OAuth account,
# rather than primary Stanford account, should go in this file. For binding of,
# and management of, OAuth accounts to WebAuth accounts, see the separate
# bind_urls.py file in the same directory as this file.

from django.conf.urls import url
from oauth import views_google, views_linkedin, views_twitter, views_facebook

urlpatterns = [
  url(r'^google/step1$', views_google.google_login_step1, name='google_step1'),
  url(r'^google/step2$', views_google.google_login_step2, name='google_step2'),
  url(r'^linkedin/step1$', views_linkedin.linkedin_login_step1, name='linkedin_step1'),
  url(r'^linkedin/step2$', views_linkedin.linkedin_login_step2, name='linkedin_step2'),
  url(r'^twitter/step1$', views_twitter.twitter_login_step1, name='twitter_step1'),
  url(r'^twitter/step2$', views_twitter.twitter_login_step2, name='twitter_step2'),
  url(r'^facebook/step1$', views_facebook.facebook_login_step1, name='facebook_step1'),
  url(r'^facebook/step2$', views_facebook.facebook_login_step2, name='facebook_step2'),
]


# -*- coding: utf-8 -*-
"""
Created on Wed Jan 15 21:41:05 2020

@author: Adesiji
"""

class EnglishRuler:
    def __init__(self, num_inches, major_length):
        self.__num_inches = num_inches
        self.__major_length = major_length

    #draw line method
    def draw_line(self, tick_length, tick_label=''):
        line ='-'*tick_length
        if tick_label:
            line += ''+tick_label
        print(line)

    #draw interval method
    def draw_interval(self, center_length):
        if center_length>0:
            self.draw_interval(center_length - 1)
            self.draw_line(center_length)
            self.draw_interval(center_length - 1)

    #draw ruler method
    def draw_ruler(self):
        self.draw_line(self.__major_length, '0')
        for j in range(1, 1+self.__num_inches):
            self.draw_interval(self.__major_length- 1)
            self.draw_line(self.__major_length, str(j))

if __name__ == '__main__':
    ruler = EnglishRuler(4,5)
    ruler.draw_ruler()


"""This is the code to read and write from the BNO055 IMU that we use.

An IMU, or Inertial Measurement Unit, is a device that takes data from
3 accelerometers and 3 gyros (for the 3 different axis) and converts it
into your orientation in 3 dimensions. We use this in order to get our
heading on the field, which is useful for *field orienting* the robot
as well as holding our heading.
"""

import enum
import math
import time

import hal
import wpilib

from .imu import IMU

class BNO055(IMU):
    """Class to read Euler values in radians from a BNO055 over I2C."""

    # i2c addresses
    # a is when the com3 in input is low
    # b is when it is high
    ADDRESS_A = 0x28
    ADDRESS_B = 0x29

    class Register(enum.IntEnum):
        """Register addresses."""

        CHIP_ID = 0x00
        ACCEL_REV_ID = 0x01
        MAG_REV_ID = 0x02
        GYRO_REV_ID = 0x03
        SW_REV_ID_LSB = 0x04
        SW_REV_ID_MSB = 0x05
        BL_REV_ID = 0x06

        PAGE_ID = 0x07

        ACCEL_DATA_X_LSB = 0x08
        ACCEL_DATA_X_MSB = 0x09
        ACCEL_DATA_Y_LSB = 0x0A
        ACCEL_DATA_Y_MSB = 0x0B
        ACCEL_DATA_Z_LSB = 0x0C
        ACCEL_DATA_Z_MSB = 0x0D

        MAG_DATA_X_LSB = 0x0E
        MAG_DATA_X_MSB = 0x0F
        MAG_DATA_Y_LSB = 0x10
        MAG_DATA_Y_MSB = 0x11
        MAG_DATA_Z_LSB = 0x12
        MAG_DATA_Z_MSB = 0x13

        GYRO_DATA_X_LSB = 0x14
        GYRO_DATA_X_MSB = 0x15
        GYRO_DATA_Y_LSB = 0x16
        GYRO_DATA_Y_MSB = 0x17
        GYRO_DATA_Z_LSB = 0x18
        GYRO_DATA_Z_MSB = 0x19

        EULER_H_LSB = 0x1A  # euler heading, least significant bit
        EULER_H_MSB = 0x1B  # euler heading, most significant bit
        EULER_P_LSB = 0x1C  # euler pitch, least significant bit
        EULER_P_MSB = 0x1D  # euler pitch, most significant bit
        EULER_R_LSB = 0x1E  # euler roll, least significant bit
        EULER_R_MSB = 0x1F  # euler roll, most significant bit

        QUATERNION_DATA_W_LSB = 0x20
        QUATERNION_DATA_W_MSB = 0x21
        QUATERNION_DATA_X_LSB = 0x22
        QUATERNION_DATA_X_MSB = 0x23
        QUATERNION_DATA_Y_LSB = 0x24
        QUATERNION_DATA_Y_MSB = 0x25
        QUATERNION_DATA_Z_LSB = 0x26
        QUATERNION_DATA_Z_MSB = 0x27

        LINEAR_ACCEL_DATA_X_LSB = 0x28
        LINEAR_ACCEL_DATA_X_MSB = 0x29
        LINEAR_ACCEL_DATA_Y_LSB = 0x2A
        LINEAR_ACCEL_DATA_Y_MSB = 0x2B
        LINEAR_ACCEL_DATA_Z_LSB = 0x2C
        LINEAR_ACCEL_DATA_Z_MSB = 0x2D

        GRAVITY_DATA_X_LSB = 0x2E
        GRAVITY_DATA_X_MSB = 0x2F
        GRAVITY_DATA_Y_LSB = 0x30
        GRAVITY_DATA_Y_MSB = 0x31
        GRAVITY_DATA_Z_LSB = 0x32
        GRAVITY_DATA_Z_MSB = 0x33

        TEMP = 0x34

        CALIB_STAT = 0x35
        SELFTEST_RESULT = 0x36
        INTR_STAT = 0x37

        SYS_CLK_STAT = 0x38
        SYS_STAT = 0x39
        SYS_ERR = 0x3A

        UNIT_SEL = 0x3B  # address used to select the unit outputs

        DATA_SELECT = 0x3C

        OPR_MODE = 0x3D  # the address used to select what sensors to use for the gyro outputs

        PWR_MODE = 0x3E

        SYS_TRIGGER = 0x3F
        TEMP_SOURCE = 0x40

        AXIS_MAP_CONFIG = 0x41
        AXIS_MAP_SIGN = 0x42

        SIC_MATRIX_0_LSB = 0x43
        SIC_MATRIX_0_MSB = 0x44
        SIC_MATRIX_1_LSB = 0x45
        SIC_MATRIX_1_MSB = 0x46
        SIC_MATRIX_2_LSB = 0x47
        SIC_MATRIX_2_MSB = 0x48
        SIC_MATRIX_3_LSB = 0x49
        SIC_MATRIX_3_MSB = 0x4A
        SIC_MATRIX_4_LSB = 0x4B
        SIC_MATRIX_4_MSB = 0x4C
        SIC_MATRIX_5_LSB = 0x4D
        SIC_MATRIX_5_MSB = 0x4E
        SIC_MATRIX_6_LSB = 0x4F
        SIC_MATRIX_6_MSB = 0x50
        SIC_MATRIX_7_LSB = 0x51
        SIC_MATRIX_7_MSB = 0x52
        SIC_MATRIX_8_LSB = 0x53
        SIC_MATRIX_8_MSB = 0x54

        ACCEL_OFFSET_X_LSB = 0x55
        ACCEL_OFFSET_X_MSB = 0x56
        ACCEL_OFFSET_Y_LSB = 0x57
        ACCEL_OFFSET_Y_MSB = 0x58
        ACCEL_OFFSET_Z_LSB = 0x59
        ACCEL_OFFSET_Z_MSB = 0x5A

        MAG_OFFSET_X_LSB = 0x5B
        MAG_OFFSET_X_MSB = 0x5C
        MAG_OFFSET_Y_LSB = 0x5D
        MAG_OFFSET_Y_MSB = 0x5E
        MAG_OFFSET_Z_LSB = 0x5F
        MAG_OFFSET_Z_MSB = 0x60

        GYRO_OFFSET_X_LSB = 0x61
        GYRO_OFFSET_X_MSB = 0x62
        GYRO_OFFSET_Y_LSB = 0x63
        GYRO_OFFSET_Y_MSB = 0x64
        GYRO_OFFSET_Z_LSB = 0x65
        GYRO_OFFSET_Z_MSB = 0x66

        ACCEL_RADIUS_LSB = 0x67
        ACCEL_RADIUS_MSB = 0x68
        MAG_RADIUS_LSB = 0x69
        MAG_RADIUS_MSB = 0x6A

    class OperationMode(enum.IntEnum):
        """Operation modes. Changes what sensors it uses and how it fuses them."""

        CONFIG = 0x00
        ACCONLY = 0x01
        MAGONLY = 0x02
        GYRONLY = 0x03
        ACCMAG = 0x04
        ACCGYRO = 0x05
        MAGGYRO = 0x06
        AMG = 0x07
        IMUPLUS = 0x08
        COMPASS = 0x09
        M4G = 0x0A
        NDOF_FMC_OFF = 0x0B
        NDOF = 0x0C

    class PowerMode(enum.IntEnum):
        NORMAL = 0x00
        LOWPOWER = 0x01
        SUSPEND = 0x02

    class AxisMapConfigMode(enum.IntEnum):
        """Axis map configuration modes."""

        P0 = 0x21
        P1 = 0x22
        P2 = 0x23
        P3 = 0x24
        P4 = 0x25
        P5 = 0x26
        P6 = 0x27
        P7 = 0x28

    class AxisMapSign(enum.IntEnum):
        P0 = 0x04
        P1 = 0x00
        P2 = 0x06
        P3 = 0x02
        P4 = 0x03
        P5 = 0x01
        P6 = 0x07
        P7 = 0x05

    # the units that we want and the index in the unit select register that corresponds to it
    UNIT_SEL_ACC_UNIT = 0  # m/s
    UNIT_SEL_ACC_UNIT_INDEX = 0
    UNIT_SEL_GYR_UNIT = 1  # rad/s
    UNIT_SEL_GYR_UNIT_INDEX = 1
    UNIT_SEL_EUL_UNIT = 1  # rad
    UNIT_SEL_EUL_UNIT_INDEX = 2
    UNIT_SEL_TEMP_UNIT = 0  # celcius
    UNIT_SEL_TEMP_UNIT_INDEX = 4
    UNIT_SEL_ORI_UNIT = 1  # android orientation mode, pitch turning clockwise decreases values
    UNIT_SEL_ORI_UNIT_INDEX = 7
    UNIT_SEL_LIST = [
        (UNIT_SEL_ACC_UNIT, UNIT_SEL_ACC_UNIT_INDEX),
        (UNIT_SEL_GYR_UNIT, UNIT_SEL_GYR_UNIT_INDEX),
        (UNIT_SEL_EUL_UNIT, UNIT_SEL_EUL_UNIT_INDEX),
        (UNIT_SEL_TEMP_UNIT, UNIT_SEL_TEMP_UNIT_INDEX),
        (UNIT_SEL_ORI_UNIT, UNIT_SEL_ORI_UNIT_INDEX),
    ]

    def __init__(self, port: wpilib.I2C.Port = None, address: int = None) -> None:
        if address is None:
            address = self.ADDRESS_A
        if port is None:
            port = wpilib.I2C.Port.kMXP

        sim_port = None
        if hal.isSimulation():
            from .bno055_sim import BNO055Sim
            sim_port = BNO055Sim()

        self.i2c = wpilib.I2C(port, address, sim_port)

        # set the units that we want
        self.offset = 0.0
        current_units = self.i2c.read(self.Register.UNIT_SEL, 1)[0]
        for wanted, index in self.UNIT_SEL_LIST:
            if wanted == 1:
                current_units = current_units | (1 << index)
            elif wanted == 0:
                current_units = current_units & ~(1 << index)
        self.i2c.write(self.Register.UNIT_SEL, current_units)
        self.setOperationMode(self.OperationMode.IMUPLUS)  # accelerometer and gyro
        self.reverse_axis(False, False, False)
        self.cache_heading()

    def cache_heading(self):
        """Cache the heading for the current timestep to prevent continually polling I2C."""
        self.timestep_cached_heading = self.getRawHeading()
        self.timestep_cached_heading_tm = time.monotonic()

    def reverse_axis(self, x: bool, y: bool, z: bool) -> None:
        """Reverse the specified axis directions."""
        current_directions = self.i2c.read(self.Register.AXIS_MAP_SIGN, 1)[0]
        if x:
            current_directions |= (1 << 2)
        else:
            current_directions &= ~(1 << 2)
        if y:
            current_directions |= (1 << 1)
        else:
            current_directions &= ~(1 << 1)
        if z:
            current_directions |= (1 << 0)
        else:
            current_directions &= ~(1 << 0)
        self.i2c.write(self.Register.AXIS_MAP_SIGN, current_directions)

    def setOperationMode(self, mode: OperationMode) -> None:
        mode = self.OperationMode(mode)
        self.i2c.write(self.Register.OPR_MODE, mode.value)

    def getAngle(self) -> float:
        return self.getHeading()

    def getAngles(self) -> tuple:
        """Return the (heading, pitch, roll) of the gyro."""
        return self.getHeading(), self.getPitch(), self.getRoll()

    def getHeading(self) -> float:
        if time.monotonic() - self.timestep_cached_heading_tm > 1/100:
            self.cache_heading()
        angle = self.timestep_cached_heading - self.offset
        return math.atan2(math.sin(angle), math.cos(angle))

    def getHeadingTime(self) -> float:
        """Get the time that the heading as returned by getHeading was cached at."""
        return self.timestep_cached_heading_tm

    def getRawHeading(self) -> float:
        return -self.getEuler(self.Register.EULER_H_LSB)

    def getPitch(self) -> float:
        return self.getEuler(self.Register.EULER_P_LSB)

    def getRoll(self) -> float:
        return self.getEuler(self.Register.EULER_R_LSB)

    def getEuler(self, start_register: int) -> float:
        euler_bytes = self.i2c.read(start_register, 2)
        euler_int = int.from_bytes(euler_bytes, 'little', signed=True)
        return euler_int / 900.0

    def getHeadingRate(self) -> float:
        return -self.getEuler(self.Register.GYRO_DATA_Z_LSB)

    def resetHeading(self, heading: float = 0) -> None:
        self.offset = self.getRawHeading() - heading


from typing import NamedTuple, List, Any, Optional

from plenum.common.exceptions import SuspiciousNode

# General recommendation for (naming) internal messages is follows:
# - internal messages are basically events, not commands
# - so in most cases from name it should be clear that "something happened"
# - in some cases message names may indicate that "something needs to happen"
# - avoid names that tell "do something", messages are not commands
# - avoid names that are just nouns, messages are not "things"

RequestPropagates = NamedTuple('RequestPropagates',
                               [('bad_requests', List)])

BackupSetupLastOrdered = NamedTuple('BackupSetupLastOrdered',
                                    [('inst_id', int)])

NeedMasterCatchup = NamedTuple('NeedMasterCatchup', [])

NeedBackupCatchup = NamedTuple('NeedBackupCatchup',
                               [('inst_id', int),
                                ('caught_up_till_3pc', tuple)])

CheckpointStabilized = NamedTuple('CheckpointStabilized',
                                  [('last_stable_3pc', tuple)])

RaisedSuspicion = NamedTuple('RaisedSuspicion',
                             [('inst_id', int),
                              ('ex', SuspiciousNode)])

PreSigVerification = NamedTuple('PreSigVerification',
                                [('cmsg', Any)])

MissingMessage = NamedTuple('MissingMessage',
                            [('msg_type', str),
                             ('key', tuple),
                             ('inst_id', int),
                             ('dst', List[str]),
                             ('stash_data', Optional[tuple])])

# by default view_no for StartViewChange is None meaning that we move to the next view
NeedViewChange = NamedTuple('NeedViewChange',
                            [('view_no', int)])
NeedViewChange.__new__.__defaults__ = (None,) * len(NeedViewChange._fields)

ViewChangeStarted = NamedTuple('ViewChangeStarted',
                               [('view_no', int)])

NewViewAccepted = NamedTuple('NewViewAccepted',
                             [('view_no', int),
                              ('view_changes', list),
                              ('checkpoint', object),
                              ('batches', list)])

NewViewCheckpointsApplied = NamedTuple('NewViewCheckpointsApplied',
                                       [('view_no', int),
                                        ('view_changes', list),
                                        ('checkpoint', object),
                                        ('batches', list)])

ReOrderedInNewView = NamedTuple('ReOrderedInNewView', [])

CatchupFinished = NamedTuple('CatchupFinished', [('last_caught_up_3PC', tuple),
                                                 ('master_last_ordered', tuple)])

CatchupCheckpointsApplied = NamedTuple('CatchupCheckpointsApplied', [('last_caught_up_3PC', tuple),
                                                                     ('master_last_ordered', tuple)])

StartViewChange = NamedTuple('StartViewChange', [('view_no', int)])


from lib import Lib
from ev3dev import ev3
import time

class Dev:
    def __init__(self, lib):
        self.l = lib

    def run(self):
        print("{:^30}".format("You are in DEVELOPER mode"))
        print('-'*30)
        self.prompt()

    def prompt(self):
        l = self.l
        cmd = input("What command would you like to run?\nCMD: ")

        if cmd == 'run':
            speed = input("What speed do you want to run at?\nSpeed: ")
            t = input("What time do you want to run it for?\nTime: ")
            # No input
            if (len(speed) == 0):
                speed = 500
            else:
                speed = int(speed)
            if (len(t) == 0):
                t = 1000
            else:
                t = int(t)
            l.move(t, speed_sp=speed)
        elif cmd == 'left':
            l.move(500, use_left=True, use_right=False, speed_sp=500)
            l.move(500, use_left=True, use_right=False, speed_sp=-500)
        elif cmd == 'right':
            l.move(500, use_left=False, use_right=True, speed_sp=500)
            l.move(500, use_left=False, use_right=True, speed_sp=-500)
        elif cmd == 'sonar':
            btn = ev3.Button()
            sonar = ev3.UltrasonicSensor(ev3.INPUT_1)
            sonar.connected
            sonar.mode = 'US-DIST-CM'
            def on_down(state):
                print("Down pressed;", state)
                print(str(sonar.value()))
            btn.on_down = on_down
            while not btn.backspace:
                print(str(sonar.value()))
                time.sleep(0.1)
        elif cmd == 'position':
            final = float(input("Final position: "))
            l.move_to_position(final)
        elif cmd == 'test tacho backforth':
            runs = int(input("Number of runs: "))
            print("Running {} times".format(runs))
            btn = ev3.Button()
            for i in range(1, runs + 1):
                print("Run # "+str(i))
                l.move_to_position(0)
                l.wait_for_motors()
                while not btn.down:
                    time.sleep(0.2)
                l.move_to_position(5000)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_to_position(2000)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_to_position(3500)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_to_position(0)
                l.wait_for_motors()
                print("Back at initial position")
        elif cmd == 'test sonar backforth':
            runs = int(input("Number of runs: "))
            print("Running {} times".format(runs))
            btn = ev3.Button()
            for i in range(1, runs + 1):
                print("Run # "+str(i))
                while not btn.down:
                    time.sleep(0.2)
                initial = l.sonar.value()
                time.sleep(2.0)
                l.move_until(150)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_until(450)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_until(250)
                l.wait_for_motors()
                time.sleep(1.0)
                l.move_until(initial)
                l.wait_for_motors()
                print("Back at initial position")
        elif cmd == 'demo':
            btn = ev3.Button()
            shelf_distance = 960
            l.move_to_position(0)
            l.wait_for_motors()
            while not btn.down:
                pos = int(input("Position: "))
                l.move_to_position(pos * shelf_distance)
                l.wait_for_motors()
        elif cmd == 'until touch':
            l.until_touch()
        elif cmd == 'until':
            final = float(input("Final position: "))
            l.move_until(final)
        elif cmd == 'exit':
            exit()
        else:
            print("I don't recognize that command, try again.")

        self.prompt()


'''
Given two strings, find the longest common subsequence (LCS).

Your code should return the length of LCS.

Example
Example 1:
	Input:  "ABCD" and "EDCA"
	Output:  1

	Explanation:
	LCS is 'A' or  'D' or 'C'

Example 2:
	Input: "ABCD" and "EACB"
	Output:  2

	Explanation:
	LCS is "AC"
Clarification
What's the definition of Longest Common Subsequence?

https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
http://baike.baidu.com/view/2020307.htm

'''
class Solution:
    """
    @param A: A string
    @param B: A string
    @return: The length of longest common subsequence of A and B
    """

    def longestCommonSubsequence(self, A, B):
        # write your code here
        if not A or not B:
            return 0

        m, n = len(A), len(B)
        dp = [[0] * (n + 1) for _ in range(m + 1)]

        for i in range(1, m + 1):
            for j in range(1, n + 1):
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
                if A[i - 1] == B[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                    # dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1)

        return dp[m][n]


import random

def bjscore(entered_hand):
    hand = entered_hand[:]
    score = 0
    soft = False
    for i in range(len(hand)):
        if (hand[i] == 'T' or hand[i] == 'J' or hand[i] == 'Q' or hand[i] == 'K'):
            score += 10
            hand[i] = 'X'
    for i in range(len(hand)):
        if (hand[i] != 'A' and hand[i] != 'X'):
            score += int(hand[i])
            hand[i] = 'X'
    for i in range(len(hand)):
        if (hand[i] != 'X'):
            if score + 11 > 21:
                score += 1
            else:
                score += 11
                soft = True
    if score > 21:
        soft = False
    return (score, soft)

class Deck():
    def __init__(self):
        self.deck = []
        for i in range(4):
            self.deck.append('A')
            self.deck.append('K')
            self.deck.append('Q')
            self.deck.append('J')
            self.deck.append('T')
            self.deck.append('9')
            self.deck.append('8')
            self.deck.append('7')
            self.deck.append('6')
            self.deck.append('5')
            self.deck.append('4')
            self.deck.append('3')
            self.deck.append('2')

    def shuffle(self):
        for i in range(len(self.deck) * 2):
            number = random.randint(0, 51)
            tmp = self.deck[i % 52]
            self.deck[i % 52] = self.deck[number]
            self.deck[number] = tmp

    def __repr__(self):
        the_deck = ''
        for i in range(len(self.deck)):
            the_deck += (self.deck[i] + ' ')

        return the_deck

class Game():
    def __init__(self):
        self.deal = Deck()
        self.info = {}
        information = []
        for i in range(22):
            information.append([[0,0,0,0,0], [0,0,0,0,0]])# No hit, hit, 2 hit. losses, ties, wins, blackjacks
        for item in self.deal.deck:
            self.info[item] = information[:] # Key is shown card, info is array of hand points as index, then blackjacks, no hit wins, no hit ties, no hit losses, 1 hit wins , 2 hit wins, total hands

    def play(self):
        self.deal.shuffle()
        dealer = [self.deal.deck[0], self.deal.deck[1]]
        score = bjscore(dealer)
        i = 2
        while score[0] < 17 or (score[1] and score[0] == 17):
            dealer.append(self.deal.deck[i])
            i += 1
            score = bjscore(dealer)

        dealer_score = score[0]
        #print('dealer score: ' + str(dealer_score) + str(dealer))
        x = self.info[self.deal.deck[0]]
        player = [self.deal.deck[-1], self.deal.deck[-2]]
        score = bjscore(player)
        i = 1
        while score[0] < 11:
            player.append(self.deal.deck[-2 - i])
            i += 1
            score = bjscore(player)
        initial_player_score = score[0]
        maximum = i
        i = 0
        while i < 2:
            if score[0] > 21:
                x[initial_player_score][i][0] += 1
            else:
                if score[0] == 21:
                    x[initial_player_score][i][3] += 1
                if score[0] > dealer_score:
                    x[initial_player_score][i][2] += 1
                if score[0] == dealer_score:
                    x[initial_player_score][i][1] += 1
                if score[0] < dealer_score and dealer_score < 22:
                    x[initial_player_score][i][0] += 1
                if score[0] < dealer_score and dealer_score > 21:
                    x[initial_player_score][i][2] += 1
            x[initial_player_score][i][4] += 1
            i += 1
            player.append(self.deal.deck[-2 - maximum])
            maximum += 1
            score = bjscore(player)
        self.info[self.deal.deck[0]] = x

    def trial(self, trials):
        for i in range(trials):
            self.play()

    def get_stats(self, shown):
        info = self.info[shown]
        for j in range(22):
            i = 0
            if (info[j][i][4] != 0):
                print(j)
                print("No hits:")
                print("Win %: " + str(info[j][i][2] / info[j][i][4] * 100))
                print("Tie %: " + str(info[j][i][1] / info[j][i][4] * 100))
                print("Lose %: " + str(info[j][i][0] / info[j][i][4] * 100))
                print("BlackJack %: " + str(info[j][i][3] / info[j][i][4] * 100))
                print("Games: " + str(info[j][i][4]) + '\n')
            i = 1
            if (info[j][i][4] != 0):
                print("One hits:")
                print("Win %: " + str(info[j][i][2] / info[j][i][4] * 100))
                print("Tie %: " + str(info[j][i][1] / info[j][i][4] * 100))
                print("Lose %: " + str(info[j][i][0] / info[j][i][4] * 100))
                print("BlackJack %: " + str(info[j][i][3] / info[j][i][4] * 100))
                print("Games: " + str(info[j][i][4]) + '\n')

    def get_all_stats(self):
        storage = {}
        for key in self.info:
            switch_found = False
            for item in range(len(self.info[key])):
                if not switch_found and (self.info[key][item][0][2] + self.info[key][item][0][1] > self.info[key][item][1][2] + self.info[key][item][1][1]):
                    switch_found = True
                    storage[key] = item
        for key in storage:
            print("The number where you should stop hitting given that a " + str(key) + " is showing is " + str(storage[key]))

new_game = Game()
#This is how many trials will be done.
new_game.trial(10000)
#Enter in what card the dealer is showing
new_game.get_stats("A")