Beispiel #1
0
def plants():
    if request.method == "GET":
        plants = []
        plantNames = []
        with connect("plantapp.db") as con: # Select plants that user is growing
            db = con.cursor()
            query = db.execute("SELECT plantid FROM plantgrowth WHERE username=?", [session["username"]])
            for row in query:
                plants.append(row[0])
            for plantid in plants:
                query = db.execute("SELECT name FROM plants WHERE plantid = ?", [plantid])
                plantNames.append(query.fetchall()[0][0])
            con.commit()
        return render_template("plants.html", plants=plantNames, username=session["username"])
    else:
        plant = request.form.get("planttype") # Get plant name from form
        if len(plant) < 1: # Check name is valid
            return redirect("/plants")
        with connect("plantapp.db") as con:
            db = con.cursor()
            query = db.execute("SELECT plantid FROM plants WHERE name = ?", [plant]) 
            if query.fetchall() == []: # Check to see if plant name already exists in DB
                db.execute("INSERT INTO plants (name) VALUES (?)", [plant]) # If no, insert plant into DB
                con.commit()
            db.execute("INSERT INTO plantgrowth (plantid, username) VALUES ((SELECT plantid FROM plants WHERE name = ?), ?)", [plant, session["username"]]) # Insert row for plant associated with user
            con.commit()
        return redirect("/plants")
Beispiel #2
0
def main(inventory, verbose):
    parsed_inventory = helpers.parse_yaml(inventory)
    password = getpass.getpass('Please enter a password: '******'password'] = password
        config = helpers.run_show(params, COMMAND, verbose=verbose)
        configs[device] = config

    parsed_vrrp_dict = parse_vrrp(configs, VRRP_REGEX)

    for device, params in parsed_inventory.items():
        generated_config = generate_config(parsed_vrrp_dict[device])
        connection = helpers.connect(address=params['address'],
                                     username=params['username'],
                                     password=params['password'],
                                     port=params['port'])
        connection.login()
        connection.configure()
        print(device)
        print(generated_config)
        actions = helpers.run_commands(connection,
                                       generated_config,
                                       verbose=verbose)
        helpers.commit_and_save(connection, actions, verbose=True)
        connection.exit()
        connection.logout()
Beispiel #3
0
def register():
    if request.method == "POST":
        email = request.form.get("r_email")
        username = request.form.get("r_username")
        password = request.form.get("r_password")
        confirmation = request.form.get("r_confirmation")
        if len(username) < 1:
            return {"response" : "Username not valid"}
            # return username not valid
        if password != confirmation:
            #todo return passwords dont match
            return {"response" : "Passwords do not match"}
        with connect("plantapp.db") as con:
            db = con.cursor()
            passhash = generate_password_hash(password)
            query = db.execute("SELECT username FROM users WHERE username = ?", [username])
            for row in query:
                if row[0] == username:
                    # todo return username exists
                    return {"response" : "Username already registered"}
            query = db.execute("SELECT email FROM users WHERE email = ?", [email])
            for row in query:
                if row[0] == email:
                    #todo return email exists
                    return {"response" : "Email already registered"}
            query = db.execute("INSERT INTO users (username, email, password) VALUES (?, ?, ?)", [username, email, passhash])
            con.commit()   
        return {"response": "OK"}           
    else:
        session.clear()
        return render_template("register.html")
Beispiel #4
0
def create_unit_superusers():
    # The leader creates and updates accounts for nodes, using the
    # encrypted password they provide in relations.PeerRelation. We
    # don't end up with unencrypted passwords leaving the unit, and we
    # don't need to restart Cassandra in no-auth mode which is slow and
    # I worry may cause issues interrupting the bootstrap.
    if not coordinator.relid:
        return  # No peer relation, no requests yet.

    created_units = helpers.get_unit_superusers()
    uncreated_units = [
        u for u in hookenv.related_units(coordinator.relid)
        if u not in created_units
    ]
    for peer in uncreated_units:
        rel = hookenv.relation_get(unit=peer, rid=coordinator.relid)
        username = rel.get('username')
        pwhash = rel.get('pwhash')
        if not username:
            continue
        hookenv.log('Creating {} account for {}'.format(username, peer))
        with helpers.connect() as session:
            helpers.ensure_user(session, username, pwhash, superuser=True)
        created_units.add(peer)
        helpers.set_unit_superusers(created_units)
Beispiel #5
0
def sub_connect():
    global ftp
    global remote_dirs
    global remote_files
    global status
    ftp, remote_dirs, remote_files = helpers.connect(host=host_entry.get(), username=username_entry.get(),
                                                     passwd=passwd_entry.get(),
                                                     port=port_entry.get())
    print(f'Remote Dirs: {remote_dirs}')
    print(f'Remote Files: {remote_files}')
    # clear status frame
    for widget in status_frame.winfo_children():
        widget.destroy()
    # set status to Connected
    import time
    status = 'Connected'
    status_label = Label(status_frame, text=f"Status: {status}", padx=10, pady=10)
    status_label.grid(stick=W + E)
    # time.sleep(5)
    #destroy other widgets
    for widget in status_frame.winfo_children():
        widget.destroy()
    # set status to Ready
    status = 'Ready'
    status_label = Label(status_frame, text=f"Status: {status}", padx=10, pady=10)
    status_label.grid(stick=W + E)
    global remote_server_window
    # remote_server_window = helpers.new_window()
    remote_server_window = remote_server.RemoteServer(geometry="905x805",remote_dirs=remote_dirs, remote_files=remote_files, ftpObj=ftp)
    global running_state
    running_state = 'running'
    return running()
Beispiel #6
0
def reset_default_password():
    if hookenv.leader_get('default_admin_password_changed'):
        hookenv.log('Default admin password already changed')
        return

    # Cassandra ships with well known credentials, rather than
    # providing a tool to reset credentials. This is a huge security
    # hole we must close.
    try:
        # We need a big timeout here, as the cassandra user actually
        # springs into existence some time after Cassandra has started
        # up and is accepting connections.
        with helpers.connect('cassandra',
                             'cassandra',
                             timeout=120,
                             auth_timeout=120) as session:
            # But before we close this security hole, we need to use these
            # credentials to create a different admin account for the
            # leader, allowing it to create accounts for other nodes as they
            # join. The alternative is restarting Cassandra without
            # authentication, which this charm will likely need to do in the
            # future when we allow Cassandra services to be related together.
            helpers.status_set('maintenance',
                               'Creating initial superuser account')
            username, password = helpers.superuser_credentials()
            pwhash = helpers.encrypt_password(password)
            helpers.ensure_user(session, username, pwhash, superuser=True)
            helpers.set_unit_superusers([hookenv.local_unit()])

            helpers.status_set('maintenance',
                               'Changing default admin password')
            helpers.query(session, 'ALTER USER cassandra WITH PASSWORD %s',
                          cassandra.ConsistencyLevel.ALL, (host.pwgen(), ))
    except cassandra.AuthenticationFailed:
        hookenv.log('Default superuser account already reset')
        try:
            with helpers.connect():
                hookenv.log("Leader's superuser account already created")
        except cassandra.AuthenticationFailed:
            # We have no known superuser credentials. Create the account
            # the hard, slow way. This will be the normal method
            # of creating the service's initial account when we allow
            # services to be related together.
            helpers.create_unit_superuser_hard()

    hookenv.leader_set(default_admin_password_changed=True)
def reset_default_password():
    if hookenv.leader_get('default_admin_password_changed'):
        hookenv.log('Default admin password already changed')
        return

    # Cassandra ships with well known credentials, rather than
    # providing a tool to reset credentials. This is a huge security
    # hole we must close.
    try:
        # We need a big timeout here, as the cassandra user actually
        # springs into existence some time after Cassandra has started
        # up and is accepting connections.
        with helpers.connect('cassandra', 'cassandra',
                             timeout=120, auth_timeout=120) as session:
            # But before we close this security hole, we need to use these
            # credentials to create a different admin account for the
            # leader, allowing it to create accounts for other nodes as they
            # join. The alternative is restarting Cassandra without
            # authentication, which this charm will likely need to do in the
            # future when we allow Cassandra services to be related together.
            helpers.status_set('maintenance',
                               'Creating initial superuser account')
            username, password = helpers.superuser_credentials()
            pwhash = helpers.encrypt_password(password)
            helpers.ensure_user(session, username, pwhash, superuser=True)
            helpers.set_unit_superusers([hookenv.local_unit()])

            helpers.status_set('maintenance',
                               'Changing default admin password')
            helpers.query(session, 'ALTER USER cassandra WITH PASSWORD %s',
                          cassandra.ConsistencyLevel.ALL, (host.pwgen(),))
    except cassandra.AuthenticationFailed:
        hookenv.log('Default superuser account already reset')
        try:
            with helpers.connect():
                hookenv.log("Leader's superuser account already created")
        except cassandra.AuthenticationFailed:
            # We have no known superuser credentials. Create the account
            # the hard, slow way. This will be the normal method
            # of creating the service's initial account when we allow
            # services to be related together.
            helpers.create_unit_superuser_hard()

    hookenv.leader_set(default_admin_password_changed=True)
Beispiel #8
0
def needs_reset_auth_keyspace_replication():
    '''Guard for reset_auth_keyspace_replication.'''
    num_nodes = helpers.num_nodes()
    datacenter = hookenv.config()['datacenter']
    with helpers.connect() as session:
        strategy_opts = helpers.get_auth_keyspace_replication(session)
        rf = int(strategy_opts.get(datacenter, -1))
        hookenv.log('system_auth rf={!r}'.format(strategy_opts))
        # If the node count has changed, we should change the rf.
        return rf != num_nodes
Beispiel #9
0
def plantsearch():
    plants = []
    plantsearch = request.json["planttype"] # Get JSON data for plant name
    with connect("plantapp.db") as con:
        db = con.cursor()
        query = db.execute("SELECT name FROM plants WHERE name LIKE ?", ['%'+plantsearch+'%']) # Select plants containing matching string
        for row in query: # Add plants to array
            plants.append({"name": row[0]})
        con.commit()
    return {"response": plants}
Beispiel #10
0
def _publish_database_relation(relid, superuser):
    # The Casandra service needs to provide a common set of credentials
    # to a client unit. The leader creates these, if none of the other
    # units are found to have published them already (a previously elected
    # leader may have done this). The leader then tickles the other units,
    # firing a hook and giving them the opportunity to copy and publish
    # these credentials.
    username, password = _client_credentials(relid)
    if username is None:
        if hookenv.is_leader():
            # Credentials not set. The leader must generate them. We use
            # the service name so that database permissions remain valid
            # even after the relation is dropped and recreated, or the
            # juju environment rebuild and the database restored from
            # backups.
            service_name = helpers.get_service_name(relid)
            if not service_name:
                # Per Bug #1555261, we might not yet have related units,
                # so no way to calculate the remote service name and thus
                # the user.
                return  # Try again later.
            username = '******'.format(helpers.get_service_name(relid))
            if superuser:
                username += '_admin'
            password = host.pwgen()
            pwhash = helpers.encrypt_password(password)
            with helpers.connect() as session:
                helpers.ensure_user(session, username, pwhash, superuser)
            # Wake the peers, if any.
            helpers.leader_ping()
        else:
            return  # No credentials yet. Nothing to do.

    # Publish the information the client needs on the relation where
    # they can find it.
    #  - authentication credentials
    #  - address and port
    #  - cluster_name, so clients can differentiate multiple clusters
    #  - datacenter + rack, so clients know what names they can use
    #    when altering keyspace replication settings.
    config = hookenv.config()
    hookenv.relation_set(relid,
                         username=username, password=password,
                         host=helpers.rpc_broadcast_ip_address(),
                         native_transport_port=config['native_transport_port'],
                         rpc_port=config['rpc_port'],
                         cluster_name=config['cluster_name'],
                         datacenter=config['datacenter'],
                         rack=config['rack'])
Beispiel #11
0
def needs_reset_auth_keyspace_replication():
    '''Guard for reset_auth_keyspace_replication.'''
    num_nodes = helpers.num_nodes()
    n = min(num_nodes, 3)
    datacenter = hookenv.config()['datacenter']
    with helpers.connect() as session:
        strategy_opts = helpers.get_auth_keyspace_replication(session)
        rf = int(strategy_opts.get(datacenter, -1))
        hookenv.log('system_auth rf={!r}'.format(strategy_opts))
        # If the node count has increased, we will change the rf.
        # If the node count is decreasing, we do nothing as the service
        # may be being destroyed.
        if rf < n:
            return True
    return False
def needs_reset_auth_keyspace_replication():
    '''Guard for reset_auth_keyspace_replication.'''
    num_nodes = helpers.num_nodes()
    n = min(num_nodes, 3)
    datacenter = hookenv.config()['datacenter']
    with helpers.connect() as session:
        strategy_opts = helpers.get_auth_keyspace_replication(session)
        rf = int(strategy_opts.get(datacenter, -1))
        hookenv.log('system_auth rf={!r}'.format(strategy_opts))
        # If the node count has increased, we will change the rf.
        # If the node count is decreasing, we do nothing as the service
        # may be being destroyed.
        if rf < n:
            return True
    return False
Beispiel #13
0
def main(subreddit_name, num):
    # create a database connect
    #conn = create_connection(config.database)

    conn, c = connect(config.database)

    # create an instance
    reddit = praw.Reddit(client_id=config.client_id, client_secret=config.client_secret, 
                        user_agent=config.user_agent, redirect_uri=config.redirect_uri, username=config.username, 
                        password=config.password)
        
    with conn:
        # create the two tables
        create_table(conn, c, 'POSTS')
        create_table(conn, c, 'COMMENTS')
        
        #obtain an instance of this class for subreddit 
        subreddit = reddit.subreddit(subreddit_name)
        
        count = 0

        #Obtain the top N posts
        #for post in subreddit.top(limit=num):
        for post in subreddit.new(limit = num):
            count += 1
            # convert timestamp to datetime, convert the post.subreddit to str
            post_set = (post.id, post.title, post.score, str(post.subreddit), post.num_comments, \
                post.selftext, datetime.fromtimestamp(post.created))
            
            # insert the post to table 'POSTS'
            insert_subreddit(conn, c, post_set, count)
            
            submission = reddit.submission(id = post.id)
            comments = []
            for top_level_comment in submission.comments:
                try:
                    comments.append(top_level_comment.body)
                except KeyError:
                    comments = [top_level_comment.body]
            comment_set = (post.id, str(comments))

            # insert the comment to table 'COMMENTS'
            insert_comment(conn, c, comment_set, count)
        
    conn.close()
Beispiel #14
0
def login():
    if request.method == "POST":
        username = request.form.get("l_username")
        password = request.form.get("l_password")
        if len(username) < 1:
            return redirect("/")
        if len(password) < 1:
            return redirect("/")
        with connect("plantapp.db") as con:
            db = con.cursor()
            query = db.execute("SELECT password FROM users WHERE username = ?", [username])
            con.commit()
            passhash = None
            for row in query:
                passhash = row[0]
            if check_password_hash(passhash, password):
                session["username"] = username
    return redirect("/")
Beispiel #15
0
def _publish_database_relation(relid, superuser):
    # The Casandra service needs to provide a common set of credentials
    # to a client unit. The leader creates these, if none of the other
    # units are found to have published them already (a previously elected
    # leader may have done this). The leader then tickles the other units,
    # firing a hook and giving them the opportunity to copy and publish
    # these credentials.
    username, password = _client_credentials(relid)
    if username is None:
        if hookenv.is_leader():
            # Credentials not set. The leader must generate them. We use
            # the service name so that database permissions remain valid
            # even after the relation is dropped and recreated, or the
            # juju environment rebuild and the database restored from
            # backups.
            username = '******'.format(helpers.get_service_name(relid))
            if superuser:
                username += '_admin'
            password = host.pwgen()
            pwhash = helpers.encrypt_password(password)
            with helpers.connect() as session:
                helpers.ensure_user(session, username, pwhash, superuser)
            # Wake the peers, if any.
            helpers.leader_ping()
        else:
            return  # No credentials yet. Nothing to do.

    # Publish the information the client needs on the relation where
    # they can find it.
    #  - authentication credentials
    #  - address and port
    #  - cluster_name, so clients can differentiate multiple clusters
    #  - datacenter + rack, so clients know what names they can use
    #    when altering keyspace replication settings.
    config = hookenv.config()
    hookenv.relation_set(relid,
                         username=username,
                         password=password,
                         host=hookenv.unit_public_ip(),
                         native_transport_port=config['native_transport_port'],
                         rpc_port=config['rpc_port'],
                         cluster_name=config['cluster_name'],
                         datacenter=config['datacenter'],
                         rack=config['rack'])
Beispiel #16
0
def reset_auth_keyspace_replication():
    # Cassandra requires you to manually set the replication factor of
    # the system_auth keyspace, to ensure availability and redundancy.
    # We replication factor in this service's DC can be no higher than
    # the number of bootstrapped nodes. We also cap this at 3 to ensure
    # we don't have too many seeds.
    num_nodes = helpers.num_nodes()
    n = min(num_nodes, 3)
    datacenter = hookenv.config()['datacenter']
    with helpers.connect() as session:
        strategy_opts = helpers.get_auth_keyspace_replication(session)
        rf = int(strategy_opts.get(datacenter, -1))
        hookenv.log('system_auth rf={!r}'.format(strategy_opts))
        if rf != n:
            strategy_opts['class'] = 'NetworkTopologyStrategy'
            strategy_opts[datacenter] = n
            if 'replication_factor' in strategy_opts:
                del strategy_opts['replication_factor']
            helpers.set_auth_keyspace_replication(session, strategy_opts)
            helpers.repair_auth_keyspace()
            helpers.set_active()
def reset_auth_keyspace_replication():
    # Cassandra requires you to manually set the replication factor of
    # the system_auth keyspace, to ensure availability and redundancy.
    # We replication factor in this service's DC can be no higher than
    # the number of bootstrapped nodes. We also cap this at 3 to ensure
    # we don't have too many seeds.
    num_nodes = helpers.num_nodes()
    n = min(num_nodes, 3)
    datacenter = hookenv.config()['datacenter']
    with helpers.connect() as session:
        strategy_opts = helpers.get_auth_keyspace_replication(session)
        rf = int(strategy_opts.get(datacenter, -1))
        hookenv.log('system_auth rf={!r}'.format(strategy_opts))
        if rf != n:
            strategy_opts['class'] = 'NetworkTopologyStrategy'
            strategy_opts[datacenter] = n
            if 'replication_factor' in strategy_opts:
                del strategy_opts['replication_factor']
            helpers.set_auth_keyspace_replication(session, strategy_opts)
            helpers.repair_auth_keyspace()
            helpers.set_active()
def create_unit_superusers():
    # The leader creates and updates accounts for nodes, using the
    # encrypted password they provide in relations.PeerRelation. We
    # don't end up with unencrypted passwords leaving the unit, and we
    # don't need to restart Cassandra in no-auth mode which is slow and
    # I worry may cause issues interrupting the bootstrap.
    if not coordinator.relid:
        return  # No peer relation, no requests yet.

    created_units = helpers.get_unit_superusers()
    uncreated_units = [u for u in hookenv.related_units(coordinator.relid)
                       if u not in created_units]
    for peer in uncreated_units:
        rel = hookenv.relation_get(unit=peer, rid=coordinator.relid)
        username = rel.get('username')
        pwhash = rel.get('pwhash')
        if not username:
            continue
        hookenv.log('Creating {} account for {}'.format(username, peer))
        with helpers.connect() as session:
            helpers.ensure_user(session, username, pwhash, superuser=True)
        created_units.add(peer)
        helpers.set_unit_superusers(created_units)
Beispiel #19
0
def filter():
    if request.method == "GET":
        # Initialize casting lists
        co = []
        cd = []
        ca = []

        # Connect to database
        conn = sqlite3.connect("auditionstats.db")
        conn.row_factory = sqlite3.Row
        c = conn.cursor()
        user_id = (session["user_id"], )
        c.execute("SELECT * FROM auditions WHERE user_id=?", user_id)
        r = c.fetchall()

        # Populate casting lists, skipping duplicates
        for i in range(len(r)):
            if r[i]["co"] not in co and r[i]["co"] != None:
                co.append(r[i]["co"])
            if r[i]["cd"] not in cd and r[i]["cd"] != None:
                cd.append(r[i]["cd"])
            if r[i]["ca"] not in ca and r[i]["ca"] != None:
                ca.append(r[i]["ca"])

        # Sort casting lists alphabetically
        co = sorted(co)
        cd = sorted(cd)
        ca = sorted(ca)

        # Close database
        conn.close()
        return render_template("filter.html", **locals())

    # If request method = POST, filter out rows of auditions based on search criteria
    else:
        # Connect to database
        r = connect(session["user_id"])

        # Save search criteria in variables
        year = request.form.get("year")
        month = request.form.get("month")
        day = request.form.get("day")
        title = request.form.get("title")
        type_t = request.form.get("type")
        role = request.form.get("role")
        co = request.form.get("co")
        cd = request.form.get("cd")
        ca = request.form.get("ca")

        # Change these variables from bools to strings (important later)
        cb = request.form.get("cb")
        if cb:
            cb = "Called Back"
        booked = request.form.get("booked")
        if booked:
            booked = "Booked"
        self_tape = request.form.get("self_tape")
        if self_tape:
            self_tape = "Self Tape"

        # Delete rows of auditions if they don't match search criteria for date
        if year != "Year...":
            for i in range(len(r) - 1, -1, -1):
                if r[i][2][:4] != year:
                    del r[i]

        if month and month != "Month...":
            month = int(month)
            month = f"{month:02d}"
            for i in range(len(r) - 1, -1, -1):
                if r[i][2][5:7] != month:
                    del r[i]

        if day and day != "Day...":
            day = int(day)
            day = f"{day:02d}"
            for i in range(len(r) - 1, -1, -1):
                if r[i][2][8:] != day:
                    del r[i]

        # Delete rows that do not contain the criteria.
        r = search(title, 3, r)
        r = search(type_t, 4, r)
        r = search(role, 5, r)
        r = search(cd, 6, r)
        r = search(ca, 7, r)
        r = search(co, 8, r)
        r = search(self_tape, 9, r)
        r = search(cb, 10, r)
        r = search(booked, 11, r)

        # Initialize empty lists to show results
        date = []
        title = []
        type_t = []
        role = []
        cd = []
        ca = []
        co = []
        self_tape = []
        cb = []
        booked = []
        notes = []

        # Populate lists
        for i in range(len(r)):
            date.append(r[i][2])
            title.append(r[i][3])
            type_t.append(r[i][4])
            role.append(r[i][5])
            cd.append(r[i][6])
            ca.append(r[i][7])
            co.append(r[i][8])
            self_tape.append(r[i][9])
            cb.append(r[i][10])
            booked.append(r[i][11])
            notes.append(r[i][12])

        return render_template("filtered.html", **locals())
Beispiel #20
0
def stats():
    # List audition sums for each year in the database
    if request.method == "GET":
        # Connect to database
        r = connect(session["user_id"])

        # Initialize empty list of years, and a list of keys
        years = []
        keys = [
            "Year", "All", "Theatre", "TV", "Film", "Commercial", "Voiceover",
            "Co Star", "Guest Star", "Recurring", "Series Regular",
            "Supporting", "Lead", "N/A", "Self Tape", "Called Back", "Booked"
        ]

        # Populate years list
        for i in range(len(r)):
            year = r[i][2][:4]
            if year not in years:
                years.append(year)

        # Create empty dictionaries for each year
        d = [{} for x in range(len(years))]

        # Set years value to year
        for i in range(len(years)):
            d[i][keys[0]] = years[i]

        # Set rest of values to zero
        for i in range(len(years)):
            for j in range(1, len(keys)):
                d[i][keys[j]] = 0

        # Count auditions
        for i in range(len(years)):
            for j in range(len(r)):
                if years[i] == r[j][2][:4]:
                    d[i][keys[1]] += 1

        # Count the rest of the categories
        for i in range(len(d)):
            for j in range(len(r)):
                for k in range(2, len(keys)):
                    if d[i][keys[0]] == r[j][2][:4]:
                        if keys[k] in r[j]:
                            d[i][keys[k]] += 1

        return render_template("stats.html", **locals())

    # If a year is clicked:
    else:
        # Get that year
        year = request.form.get("bookingId")

        # Connect to database
        r = connect(session["user_id"])

        # Initialize keys
        keys = ["All", "Theatre", "TV", "Film", "Commercial", "Voiceover"]

        # Initialize dictionary titles
        ds = ["Total", "Booked", "Percentage"]

        # Create empty dictionaries for each of the titles
        d = [{} for x in range(len(ds))]

        # Set dict values to zero
        for i in range(len(ds)):
            for j in range(len(keys)):
                d[i][keys[j]] = 0

        # Find total auditions & auditions for each category (filling d[0])
        for i in range(len(r)):
            if year == r[i][2][:4]:
                d[0][keys[0]] += 1
                for j in range(1, len(keys)):
                    if keys[j] in r[i]:
                        d[0][keys[j]] += 1

        # Find auditions booked (filling d[1])
        for i in range(len(r)):
            if year == r[i][2][:4] and r[i][11] == "Booked":
                d[1][keys[0]] += 1
                for j in range(1, len(keys)):
                    if keys[j] in r[i]:
                        d[1][keys[j]] += 1

        # Calculate percentage (filling d[2])
        for i in range(len(keys)):
            if d[0][keys[i]] != 0:
                d[2][keys[i]] = float(d[1][keys[i]] / d[0][keys[i]])
                d[2][keys[i]] = "{:.0%}".format(d[2][keys[i]])
            else:
                d[2][keys[i]] = "N/A"

        return render_template("percentage.html", **locals())