# Path: ob2/util/config_data.py
# def get_assignment_by_name(name, default=None):
#     global _assignment_by_name
#     if _assignment_by_name is None:
#         _assignment_by_name = {assignment.name: assignment
#                                for assignment in config.assignments}
#     return _assignment_by_name[name]
# 
# Path: ob2/util/time.py
# def format_js_compatible_time(s):
#     """Converts a datetime object to serializable format for JavaScript."""
#     return s.strftime("%Y-%m-%dT%H:%M:%S%z")
# 
# def now():
#     """Gets the current datetime (with timezone) as an object."""
#     timezone_obj = pytz.timezone(config.timezone)
#     return datetime.utcnow().replace(tzinfo=pytz.utc).astimezone(timezone_obj)
# 
# def parse_time(s):
#     """Converts serializable datetime to a datetime object."""
#     return DateParser.parse(s)
# 
# Path: ob2/util/build_constants.py
# SUCCESS = 0


import numpy as np
from math import ceil, floor
from ob2.util.config_data import get_assignment_by_name
from ob2.util.time import format_js_compatible_time, now, parse_time
from ob2.util.build_constants import SUCCESS
                     ORDER BY started''', [assignment_name, SUCCESS])
        # XXX: There is no easy way to exclude builds started by staff ("super") groups.
        # But because this graph is to show the general trend, it's usually fine if staff builds
        # are included. Plus, the graph only shows up in the admin interface anyway.
        builds = [(source, score, parse_time(started)) for source, score, started in c.fetchall()]
        if not builds:
            return []
        source_set = map(lambda b: b[0], builds)
        started_time_set = map(lambda b: b[2], builds)
        min_started = min(started_time_set)
        max_started = max(started_time_set)
        assignment_min_started = parse_time(assignment.not_visible_before)
        assignment_max_started = parse_time(assignment.due_date)
        data_min = min(min_started, assignment_min_started)
        data_max = max(max_started, assignment_max_started)
        data_points = []
        best_scores_so_far = {source: 0 for source in source_set}
        time_delta = (data_max - data_min) / (num_points - 1)
        current_time = data_min
        for source, score, started_time in builds:
            while current_time < started_time:
                percentiles = np.percentile(best_scores_so_far.values(), data_keys)
                data_points.append([format_js_compatible_time(current_time)] + list(percentiles))
                current_time += time_delta
            if score is not None:
                best_scores_so_far[source] = max(score, best_scores_so_far[source])

        percentiles = list(np.percentile(best_scores_so_far.values(), data_keys))
        now_time = now()
        while current_time - (time_delta / 2) < data_max:

# Path: ob2/util/config_data.py
# def get_assignment_by_name(name, default=None):
#     global _assignment_by_name
#     if _assignment_by_name is None:
#         _assignment_by_name = {assignment.name: assignment
#                                for assignment in config.assignments}
#     return _assignment_by_name[name]
# 
# Path: ob2/util/time.py
# def format_js_compatible_time(s):
#     """Converts a datetime object to serializable format for JavaScript."""
#     return s.strftime("%Y-%m-%dT%H:%M:%S%z")
# 
# def now():
#     """Gets the current datetime (with timezone) as an object."""
#     timezone_obj = pytz.timezone(config.timezone)
#     return datetime.utcnow().replace(tzinfo=pytz.utc).astimezone(timezone_obj)
# 
# def parse_time(s):
#     """Converts serializable datetime to a datetime object."""
#     return DateParser.parse(s)
# 
# Path: ob2/util/build_constants.py
# SUCCESS = 0


# Path: ob2/util/datasets.py
import numpy as np
from math import ceil, floor
from ob2.util.config_data import get_assignment_by_name
from ob2.util.time import format_js_compatible_time, now, parse_time
from ob2.util.build_constants import SUCCESS

                     ORDER BY started''', [assignment_name, SUCCESS])
        # XXX: There is no easy way to exclude builds started by staff ("super") groups.
        # But because this graph is to show the general trend, it's usually fine if staff builds
        # are included. Plus, the graph only shows up in the admin interface anyway.
        builds = [(source, score, parse_time(started)) for source, score, started in c.fetchall()]
        if not builds:
            return []
        source_set = map(lambda b: b[0], builds)
        started_time_set = map(lambda b: b[2], builds)
        min_started = min(started_time_set)
        max_started = max(started_time_set)
        assignment_min_started = parse_time(assignment.not_visible_before)
        assignment_max_started = parse_time(assignment.due_date)
        data_min = min(min_started, assignment_min_started)
        data_max = max(max_started, assignment_max_started)
        data_points = []
        best_scores_so_far = {source: 0 for source in source_set}
        time_delta = (data_max - data_min) / (num_points - 1)
        current_time = data_min
        for source, score, started_time in builds:
            while current_time < started_time:
                percentiles = np.percentile(best_scores_so_far.values(), data_keys)
                data_points.append([format_js_compatible_time(current_time)] + list(percentiles))
                current_time += time_delta
            if score is not None:
                best_scores_so_far[source] = max(score, best_scores_so_far[source])

        percentiles = list(np.percentile(best_scores_so_far.values(), data_keys))
        now_time = now()
        while current_time - (time_delta / 2) < data_max:

            data_points.append([format_js_compatible_time(current_time)] + percentiles)