def usersPrediction(f, u, k, model, verbose=True):
    """
    Predicts the grade of a user for one film given the (users point of view based) model and the parameter k
    :param f: The film index
    :param u: The user index
    :param k: The parameter k of the k nearest neighbors algorithm
    :param model: The prediction model, as built by buildUsersModel()
    :param verbose: If set to True, status prints are made during the execution of the code
    :return: An estimation as a floating point number of the grade the user would give to the film
    The prediction is made by taking as many neighbors as possible of u, but at most k, who have seen the film f, chosen
    by decreasing order of similarity with u.
    The average of their normalized ratings, weighted by their similarities with u, is then computed as a prediction of
    the normalized grade of u for f.
    The grade is then multiplied by u's standard deviation, added to u's mean grade, and culled if necessary between 1
    and 5, to give the final estimate.
    If no neighbors of u with a positive similarity with u have seen the film f, the prediction is simply the average
    grade given by u.
    """
    count = 0
    ref_neighbors = []
    n_neighbors = len(model['sortedNeighbors'][u])
    while len(ref_neighbors) < k and count < n_neighbors:
        n, sim = model['sortedNeighbors'][u][count]
        if model['boolViewings'][f, n] == 1 and sim > 0:
            ref_neighbors.append((n, sim))
        count += 1
    if len(ref_neighbors) == 0:
        if verbose:
            print("No (correlated) neighbors have seen the film, returning average grade")
        return model['userMeans'][u]
    meanGrade = 0
    totWeights = 0
    for n, sim in ref_neighbors:
        meanGrade += (model['userMeans'][u] + model['userStdDevs'][u] * model['normRatings'][f, n]) * sim
        totWeights += sim
    meanGrade /= totWeights
    meanGrade = min(meanGrade, 5)
    meanGrade = max(meanGrade, 1)
    return meanGrade