diff --git a/helpers_root b/helpers_root
index 7629706576..a77012a630 160000
--- a/helpers_root
+++ b/helpers_root
@@ -1 +1 @@
-Subproject commit 762970657663b4d2a0692453fbc9ad2b217c3231
+Subproject commit a77012a630039408e7e860e481ff86deda1ad5b5
diff --git a/tutorial_github_causify_style/github_utils.py b/tutorial_github_causify_style/github_utils.py
index 59fc084402..bc2b85f4dc 100644
--- a/tutorial_github_causify_style/github_utils.py
+++ b/tutorial_github_causify_style/github_utils.py
@@ -1,13 +1,24 @@
+"""
+Import as:
+
+import tutorial_github_causify_style.github_utils as tgcsgiut
+"""
+
import datetime
import logging
import os
+import time
from typing import Any, Dict, List, Optional, Tuple
import github
+import helpers.hcache_simple as hcacsimp
+import matplotlib.pyplot as plt
+import pandas as pd
from tqdm import tqdm
_LOG = logging.getLogger(__name__)
+
# #############################################################################
# GitHubAPI
# #############################################################################
@@ -15,14 +26,14 @@
class GitHubAPI:
"""
- A class to initialize and manage authentication with the GitHub API using PyGithub.
+ Initialize and manage authentication with the GitHub API using PyGithub.
"""
def __init__(
self, access_token: Optional[str] = None, base_url: Optional[str] = None
):
"""
- Initialize the GitHub API client
+ Initialize the GitHub API client.
:param access_token: github personal access token; if not provided, it
is fetched from the environment variable `GITHUB_ACCESS_TOKEN`
@@ -42,7 +53,7 @@ def __init__(
def get_client(self) -> github.Github:
"""
- Return the authenticated GitHub client
+ Return the authenticated GitHub client.
:return: an instance of the authenticated PyGithub client
"""
@@ -50,7 +61,7 @@ def get_client(self) -> github.Github:
def close_connection(self) -> None:
"""
- Close the GitHub API connection
+ Close the GitHub API connection.
"""
self.github.close()
@@ -63,7 +74,7 @@ def close_connection(self) -> None:
# TODO(prahar08modi): Test the function using pytest
def get_repo_names(client: github.Github, org_name: str) -> Dict[str, List[str]]:
"""
- Retrieve a list of repositories under a specific organization
+ Retrieve a list of repositories under a specific organization.
:param client: authenticated instance of the PyGithub client
:param org_name: name of the GitHub organization
@@ -71,12 +82,15 @@ def get_repo_names(client: github.Github, org_name: str) -> Dict[str, List[str]]
- owner: name of the organization
- repositories: repository names
"""
+ # TODO: Turn the try-except into an assertion. No point in trying to recover.
try:
# Attempt to get the organization.
owner = client.get_organization(org_name)
except Exception as e:
_LOG.error("Error retrieving organization '%s': %s", org_name, e)
- raise ValueError(f"'{org_name}' is not a valid GitHub organization.") from e
+ raise ValueError(
+ f"'{org_name}' is not a valid GitHub organization."
+ ) from e
repos = [repo.name for repo in owner.get_repos()]
result = {"owner": org_name, "repositories": repos}
return result
@@ -87,7 +101,7 @@ def get_github_contributors(
client: github.Github, repo_names: List[str]
) -> Dict[str, List[str]]:
"""
- Retrieve GitHub usernames contributing to specified repositories
+ Retrieve GitHub usernames contributing to specified repositories.
:param client: authenticated instance of the PyGithub client
:param repo_names: repository names in the format 'owner/repo' to fetch
@@ -105,9 +119,7 @@ def get_github_contributors(
]
result[repo_name] = contributors
except Exception as e:
- _LOG.error(
- "Error fetching contributors for %s: %s", repo_name, e
- )
+ _LOG.error("Error fetching contributors for %s: %s", repo_name, e)
result[repo_name] = []
return result
@@ -116,12 +128,13 @@ def normalize_period_to_utc(
period: Optional[Tuple[datetime.datetime, datetime.datetime]],
) -> Tuple[Optional[datetime.datetime], Optional[datetime.datetime]]:
"""
- Convert a datetime period to UTC and ensure both dates are timezone-aware
+ Convert a datetime period to UTC and ensure both dates are timezone-aware.
:param period: start and end datetime
- :return: tuple of UTC-aware start and end datetime, or (None, None) if
- period is None
+ :return: UTC-aware start and end datetime, or (None, None) if period
+ is None
"""
+ # TODO: Code implementation-137: Use `if period is None` instead of `if not period` to check if `period` is `None`.
if not period:
return None, None
return tuple(
@@ -148,7 +161,7 @@ def get_total_commits(
"""
Fetch the number of commits made in the repositories of the specified
organization, optionally filtered by GitHub usernames and a specified time
- period
+ period.
:param client: authenticated instance of the PyGithub client
:param org_name: name of the GitHub organization
@@ -166,9 +179,7 @@ def get_total_commits(
repos_info = get_repo_names(client, org_name)
repositories = repos_info.get("repositories", [])
except Exception as e:
- _LOG.error(
- "Error retrieving repositories for '%s': %s", org_name, e
- )
+ _LOG.error("Error retrieving repositories for '%s': %s", org_name, e)
return {
"total_commits": 0,
"period": "N/A",
@@ -205,7 +216,6 @@ def get_total_commits(
"period": f"{since} to {until}" if since and until else "All time",
"commits_per_repository": commits_per_repository,
}
-
return result
@@ -214,12 +224,12 @@ def get_total_prs(
org_name: str,
usernames: Optional[List[str]] = None,
period: Optional[Tuple[datetime.datetime, datetime.datetime]] = None,
- state: str = "open",
+ state: str = "all",
) -> Dict[str, Any]:
"""
Fetch the number of pull requests made in the repositories of the specified
- organization, optionally filtered by GitHub usernames, a specified time period,
- and the state of the pull requests
+ organization, optionally filtered by GitHub usernames, a specified time
+ period, and the state of the pull requests.
:param client: authenticated instance of the PyGithub client
:param org_name: name of the GitHub organization
@@ -238,9 +248,7 @@ def get_total_prs(
repos_info = get_repo_names(client, org_name)
repositories = repos_info.get("repositories", [])
except Exception as e:
- _LOG.error(
- "Error retrieving repositories for '%s': %s", org_name, e
- )
+ _LOG.error("Error retrieving repositories for '%s': %s", org_name, e)
return {"total_prs": 0, "period": "N/A", "prs_per_repository": {}}
total_prs = 0
prs_per_repository = {}
@@ -253,37 +261,25 @@ def get_total_prs(
try:
repo = client.get_repo(f"{org_name}/{repo_name}")
repo_pr_count = 0
- # Fetch pull requests based on the specified state.
- issues = repo.get_issues(state=state, since=since)
- for issue in issues:
- if not issue.pull_request:
- # Skip if not a pull request
- continue
- try:
- pr = repo.get_pull(issue.number)
- except Exception as e:
- _LOG.warning(
- "Could not fetch PR #%d in %s: %s", issue.number, repo_name, e
- )
+ pulls = repo.get_pulls(state=state)
+ for pr in pulls:
+ if usernames and pr.user.login not in usernames:
continue
- # Ensure pr.created_at is timezone-aware in UTC.
pr_created_at = (
pr.created_at.replace(tzinfo=datetime.timezone.utc)
if pr.created_at.tzinfo is None
else pr.created_at.astimezone(datetime.timezone.utc)
)
if since and until and not (since <= pr_created_at <= until):
- # Skip pull request if it's outside the specified date range.
- continue
- if usernames and pr.user.login not in usernames:
- # Skip pull request if it's not authored by one of the specified users.
continue
repo_pr_count += 1
prs_per_repository[repo_name] = repo_pr_count
total_prs += repo_pr_count
except Exception as e:
_LOG.error(
- "Error accessing pull requests for repository '%s': %s", repo_name, e
+ "Error accessing pull requests for repository '%s': %s",
+ repo_name,
+ e,
)
prs_per_repository[repo_name] = 0
result = {
@@ -301,8 +297,8 @@ def get_prs_not_merged(
period: Optional[Tuple[datetime.datetime, datetime.datetime]] = None,
) -> Dict[str, Any]:
"""
- Fetch the count of closed but unmerged pull requests in the specified repositories
- and by the specified GitHub users within a given period
+ Fetch the count of closed but unmerged pull requests in the specified
+ repositories and by the specified GitHub users within a given period.
:param client: authenticated instance of the PyGithub client
:param org_name: name of the GitHub organization
@@ -319,9 +315,7 @@ def get_prs_not_merged(
repos_info = get_repo_names(client, org_name)
repositories = repos_info.get("repositories", [])
except Exception as e:
- _LOG.error(
- "Error retrieving repositories for '%s': %s", org_name, e
- )
+ _LOG.error("Error retrieving repositories for '%s': %s", org_name, e)
return {
"prs_not_merged": 0,
"period": "N/A",
@@ -348,9 +342,7 @@ def get_prs_not_merged(
for pr in pulls:
try:
# Print progress.
- _LOG.debug(
- "Processing PR #%d from %s", pr.number, repo_name
- )
+ _LOG.debug("Processing PR #%d from %s", pr.number, repo_name)
# Ensure PR creation date is always set before usage.
pr_created_at = (
pr.created_at if pr.created_at else datetime.datetime.min
@@ -376,14 +368,19 @@ def get_prs_not_merged(
except Exception as e:
# Skip this PR and proceed with the next one.
_LOG.error(
- "Error processing PR #%d in '%s': %s", pr.number, repo_name, e
+ "Error processing PR #%d in '%s': %s",
+ pr.number,
+ repo_name,
+ e,
)
continue
prs_per_repository[repo_name] = repo_unmerged_pr_count
total_unmerged_prs += repo_unmerged_pr_count
except Exception as e:
_LOG.error(
- "Error accessing pull requests for repository '%s': %s", repo_name, e
+ "Error accessing pull requests for repository '%s': %s",
+ repo_name,
+ e,
)
prs_per_repository[repo_name] = 0
result = {
@@ -398,11 +395,12 @@ def get_total_issues(
client: github.Github,
org_name: str,
repo_names: Optional[List[str]] = None,
- state: str = "open",
+ state: str = "all",
period: Optional[Tuple[datetime.datetime, datetime.datetime]] = None,
) -> Dict[str, Any]:
"""
- Retrieve the number of issues in the specified repositories within a given time range and state
+ Retrieve the number of issues in the specified repositories within a given
+ time range and state.
:param client: authenticated instance of the PyGithub client
:param org_name: name of the GitHub organization
@@ -428,9 +426,7 @@ def get_total_issues(
repos_info = get_repo_names(client, org_name)
repo_names = repos_info.get("repositories", [])
except Exception as e:
- _LOG.error(
- "Error retrieving repositories for '%s': %s", org_name, e
- )
+ _LOG.error("Error retrieving repositories for '%s': %s", org_name, e)
return {
"total_issues": 0,
"state": state,
@@ -452,7 +448,9 @@ def get_total_issues(
continue
# Ensure Issue creation date is timezone-aware in UTC.
issue_created_at = (
- issue.created_at if issue.created_at else datetime.datetime.min
+ issue.created_at
+ if issue.created_at
+ else datetime.datetime.min
)
if issue_created_at.tzinfo is None:
issue_created_at = issue_created_at.replace(
@@ -472,9 +470,7 @@ def get_total_issues(
repo_issue_count += 1
except Exception as e:
# Skip this issue and proceed with the next one.
- _LOG.error(
- "Error processing issue in '%s': %s", repo_name, e
- )
+ _LOG.error("Error processing issue in '%s': %s", repo_name, e)
continue
issues_per_repository[repo_name] = repo_issue_count
total_issues += repo_issue_count
@@ -526,9 +522,7 @@ def get_issues_without_assignee(
repos_info = get_repo_names(client, org_name)
repo_names = repos_info.get("repositories", [])
except Exception as e:
- _LOG.error(
- "Error retrieving repositories for '%s': %s", org_name, e
- )
+ _LOG.error("Error retrieving repositories for '%s': %s", org_name, e)
return {
"issues_without_assignee": 0,
"state": state,
@@ -549,7 +543,9 @@ def get_issues_without_assignee(
continue
# Ensure Issue creation date is timezone-aware in UTC.
issue_created_at = (
- issue.created_at if issue.created_at else datetime.datetime.min
+ issue.created_at
+ if issue.created_at
+ else datetime.datetime.min
)
if issue_created_at.tzinfo is None:
issue_created_at = issue_created_at.replace(
@@ -569,9 +565,7 @@ def get_issues_without_assignee(
if not issue.assignees:
repo_unassigned_count += 1
except Exception as e:
- _LOG.error(
- "Error processing issue in '%s': %s", repo_name, e
- )
+ _LOG.error("Error processing issue in '%s': %s", repo_name, e)
continue
issues_per_repository[repo_name] = repo_unassigned_count
issues_without_assignee += repo_unassigned_count
@@ -617,6 +611,7 @@ def get_commits_by_person(
result = get_total_commits(
client=client, org_name=org_name, usernames=[username], period=period
)
+ # TODO(False): Functions-224: Do not put computations of the output in the `return` line. Compute the output first, assign it to a variable, and then return this variable.
return {
"user": username,
"total_commits": result["total_commits"],
@@ -630,11 +625,11 @@ def get_prs_by_person(
username: str,
org_name: str,
period: Optional[Tuple[datetime.datetime, datetime.datetime]] = None,
- state: str = "open",
+ state: str = "all",
) -> Dict[str, Any]:
"""
- Fetch the number of pull requests created by a specific GitHub user
- in the given repositories and time period.
+ Fetch the number of pull requests created by a specific GitHub user in the
+ given repositories and time period.
:param client: authenticated instance of the PyGithub client
:param username: GitHub username to fetch pull request data for
@@ -656,6 +651,7 @@ def get_prs_by_person(
period=period,
state=state,
)
+ # TODO(False): Functions-224: Do not put computations of the output in the `return` line. Compute the output first, assign it to a variable, and then return this variable.
return {
"user": username,
"total_prs": result["total_prs"],
@@ -688,9 +684,599 @@ def get_prs_not_merged_by_person(
result = get_prs_not_merged(
client=client, org_name=org_name, usernames=[username], period=period
)
+ # TODO(False): Functions-224: Do not put computations of the output in the `return` line. Compute the output first, assign it to a variable, and then return this variable.
return {
"user": username,
"prs_not_merged": result["prs_not_merged"],
"period": result["period"],
"prs_per_repository": result["prs_per_repository"],
}
+
+
+def days_between(
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> List[datetime.date]:
+ """
+ Generate each date in time span.
+
+ :param period: start and end datetime
+ :return: date span
+ """
+ start_date = period[0].date()
+ end_date = period[1].date()
+ days: List[datetime.date] = []
+ current = start_date
+ while current <= end_date:
+ days.append(current)
+ current += datetime.timedelta(days=1)
+ # TODO(False): Logging-248: Use `_LOG.debug()` instead of `_LOG.info()` for tracing execution.
+ _LOG.info("Generated %d days in period.", len(days))
+ return days
+
+
+@hcacsimp.simple_cache(cache_type="json", write_through=True)
+def get_commit_datetimes_by_repo_period_intrinsic(
+ client,
+ org: str,
+ repo: str,
+ username: Optional[str],
+ since: datetime.datetime,
+ until: datetime.datetime,
+) -> List[str]:
+ """
+ Fetch commit timestamps for user in repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param since: start datetime
+ :param until: end datetime
+ :return: commit timestamps in ISO format
+ """
+ timestamps: List[str] = []
+ try:
+ repo_obj = client.get_repo(f"{org}/{repo}")
+ # Grab all commits in range, then filter by author or committer.
+ for c in repo_obj.get_commits(since=since, until=until):
+ author_login = c.author.login if c.author else None
+ committer_login = c.committer.login if c.committer else None
+ if username in (author_login, committer_login):
+ dt = c.commit.author.date
+ dt_utc = (
+ dt if dt.tzinfo else dt.replace(tzinfo=datetime.timezone.utc)
+ )
+ timestamps.append(dt_utc.isoformat())
+ _LOG.info(
+ "Fetched %d commits for %s/%s user=%s.",
+ len(timestamps),
+ org,
+ repo,
+ username,
+ )
+ except Exception as e:
+ _LOG.warning(
+ "Failed to fetch commits for %s/%s user=%s: %s.",
+ org,
+ repo,
+ username,
+ e,
+ )
+ return timestamps
+
+
+@hcacsimp.simple_cache(cache_type="json", write_through=True)
+def get_pr_datetimes_by_repo_period_intrinsic(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ since: datetime.datetime,
+ until: datetime.datetime,
+) -> List[str]:
+ """
+ Fetch pull request timestamps for user in repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param since: start datetime
+ :param until: end datetime
+ :return: PR created timestamps in ISO format
+ """
+ timestamps: List[str] = []
+ since_date = since.date().isoformat()
+ until_date = until.date().isoformat()
+ query = f"repo:{org}/{repo} is:pr author:{username} created:{since_date}..{until_date}"
+ try:
+ results = client.search_issues(query)
+ for issue in results:
+ dt = issue.created_at
+ dt_utc = dt if dt.tzinfo else dt.replace(tzinfo=datetime.timezone.utc)
+ timestamps.append(dt_utc.isoformat())
+ _LOG.info(
+ "Found %d PRs for %s/%s user=%s.",
+ len(timestamps),
+ org,
+ repo,
+ username,
+ )
+ except Exception as e:
+ _LOG.warning(
+ "PR search failed for %s/%s user=%s: %s.", org, repo, username, e
+ )
+ return timestamps
+
+
+@hcacsimp.simple_cache(cache_type="json", write_through=True)
+def get_loc_stats_by_repo_period_intrinsic(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ since: datetime.datetime,
+ until: datetime.datetime,
+) -> List[Dict[str, int]]:
+ """
+ Fetch commit LOC stats for user in repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param since: start datetime
+ :param until: end datetime
+ :return: additions, deletions in code
+ """
+ stats_list: List[Dict[str, int]] = []
+ try:
+ repo_obj = client.get_repo(f"{org}/{repo}")
+ # Grab all commits in range, then filter by author/committer.
+ for c in repo_obj.get_commits(since=since, until=until):
+ author_login = c.author.login if c.author else None
+ committer_login = c.committer.login if c.committer else None
+ if username not in (author_login, committer_login):
+ continue
+ try:
+ s = c.stats
+ except Exception:
+ _LOG.warning("Could not fetch stats for commit %s.", c.sha)
+ continue
+ dt = c.commit.author.date
+ dt_utc = dt if dt.tzinfo else dt.replace(tzinfo=datetime.timezone.utc)
+ iso = dt_utc.date().isoformat()
+ stats_list.append(
+ {"date": iso, "additions": s.additions, "deletions": s.deletions}
+ )
+ _LOG.info(
+ "Fetched LOC stats for %s/%s user=%s entries=%d.",
+ org,
+ repo,
+ username,
+ len(stats_list),
+ )
+ except Exception as e:
+ _LOG.warning(
+ "Failed to fetch LOC for %s/%s user=%s: %s.", org, repo, username, e
+ )
+ return stats_list
+
+
+def build_daily_commit_df(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> pd.DataFrame:
+ """
+ Build daily commit counts for user and repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param period: start and end datetime objects
+ :return: data with date, commits, repo, user
+ """
+ since, until = period
+ timestamps = get_commit_datetimes_by_repo_period_intrinsic(
+ client, org, repo, username, since, until
+ )
+ df = pd.DataFrame({"ts": pd.to_datetime(timestamps)})
+ df["date"] = df.ts.dt.date
+ daily = df.groupby("date").size().reset_index(name="commits")
+ all_days = pd.DataFrame({"date": days_between(period)})
+ daily = all_days.merge(daily, on="date", how="left")
+ daily["commits"] = daily["commits"].fillna(0).astype(int)
+ daily["repo"] = repo
+ daily["user"] = username
+ _LOG.info("Built daily commit DataFrame rows=%d.", len(daily))
+ return daily
+
+
+def build_daily_pr_df(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> pd.DataFrame:
+ """
+ Build daily PR counts for user and repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param period: start and end datetime objects
+ :return: data with date, prs, repo, user
+ """
+ since, until = period
+ timestamps = get_pr_datetimes_by_repo_period_intrinsic(
+ client, org, repo, username, since, until
+ )
+ df = pd.DataFrame({"ts": pd.to_datetime(timestamps)})
+ df["date"] = df.ts.dt.date
+ daily = df.groupby("date").size().reset_index(name="prs")
+ all_days = pd.DataFrame({"date": days_between(period)})
+ daily = all_days.merge(daily, on="date", how="left")
+ daily["prs"] = daily["prs"].fillna(0).astype(int)
+ daily["repo"] = repo
+ daily["user"] = username
+ _LOG.info("Built daily PR DataFrame rows=%d.", len(daily))
+ return daily
+
+
+def build_daily_loc_df(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> pd.DataFrame:
+ """
+ Build daily LOC additions and deletions for user and repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param period: start and end datetime objects
+ :return: data with date, additions, deletions, repo, user
+ """
+ since, until = period
+ # Fetch raw LOC stats list.
+ stats_list = get_loc_stats_by_repo_period_intrinsic(
+ client, org, repo, username, since, until
+ )
+ # If no stats, return zeros for full range.
+ if not stats_list:
+ all_days = pd.DataFrame({"date": days_between(period)})
+ # Initialize zeroes.
+ all_days["additions"] = all_days["date"].apply(lambda _: 0)
+ all_days["deletions"] = all_days["date"].apply(lambda _: 0)
+ # Format signs.
+ all_days["additions"] = (
+ all_days["additions"].astype(str).apply(lambda x: "+" + x)
+ )
+ all_days["deletions"] = (
+ all_days["deletions"].astype(str).apply(lambda x: "-" + x)
+ )
+ # Add context.
+ all_days["repo"] = repo
+ all_days["user"] = username
+ # TODO(False): Logging-248: Use `_LOG.debug()` instead of `_LOG.info()` for tracing execution.
+ _LOG.info("Built daily LOC DataFrame rows=%d (no data).", len(all_days))
+ return all_days
+ # Otherwise build from stats_list.
+ df = pd.DataFrame(stats_list)
+ df["date"] = pd.to_datetime(df["date"]).dt.date
+ # Sum per date.
+ daily = df.groupby("date")[["additions", "deletions"]].sum().reset_index()
+ # Ensure full date coverage.
+ all_days = pd.DataFrame({"date": days_between(period)})
+ daily = all_days.merge(daily, on="date", how="left")
+ # Fill missing and integerize.
+ daily[["additions", "deletions"]] = (
+ daily[["additions", "deletions"]].fillna(0).astype(int)
+ )
+ # Apply sign formatting.
+ daily["additions"] = daily["additions"].astype(str).apply(lambda x: "+" + x)
+ daily["deletions"] = daily["deletions"].astype(str).apply(lambda x: "-" + x)
+ # Add context.
+ daily["repo"] = repo
+ daily["user"] = username
+ # TODO(False): Logging-248: Use `_LOG.debug()` instead of `_LOG.info()` for tracing execution.
+ _LOG.info("Built daily LOC DataFrame rows=%d.", len(daily))
+ return daily
+
+
+def get_total_loc_for_period(
+ client,
+ org: str,
+ repo: str,
+ username: str,
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> Dict[str, int]:
+ """
+ Get total LOC additions and deletions for user and repo over period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repo: repository name
+ :param username: GitHub username
+ :param period: start and end datetime objects
+ :return: additions and deletions totals
+ """
+ since, until = period
+ stats = get_loc_stats_by_repo_period_intrinsic(
+ client, org, repo, username, since, until
+ )
+ total_add = sum(item["additions"] for item in stats)
+ total_del = sum(item["deletions"] for item in stats)
+ _LOG.info(
+ "Total LOC for %s/%s user=%s => +%d -%d.",
+ org,
+ repo,
+ username,
+ total_add,
+ total_del,
+ )
+ return {"additions": total_add, "deletions": total_del}
+
+
+def prefetch_periodic_user_repo_data(
+ client,
+ org: str,
+ repos: List[str],
+ users: List[str],
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> None:
+ """
+ Prefetch and cache commits, PRs, and LOC for each user and repo over
+ period.
+
+ :param client: authenticated PyGithub client
+ :param org: GitHub org name
+ :param repos: list of repository names
+ :param users: list of GitHub usernames
+ :param period: start and end datetime objects
+ """
+ # Validate org, repos, and users types.
+ if not isinstance(org, str):
+ raise ValueError(f"org must be a string, got {type(org).__name__}")
+ if not isinstance(repos, list) or not all(isinstance(r, str) for r in repos):
+ raise ValueError("repos must be a list of strings")
+ if not isinstance(users, list) or not all(isinstance(u, str) for u in users):
+ raise ValueError("users must be a list of strings")
+ start = time.time()
+ count = 0
+ since, until = period
+ # Loop over each repo and user combination.
+ for repo in repos:
+ # Ensure each repo is string.
+ if not isinstance(repo, str):
+ raise ValueError(f"Expected repo to be a string but got {repo!r}")
+ _LOG.info("Starting prefetch for repo %s.", repo)
+ for user in users:
+ # Ensure each user is string.
+ if not isinstance(user, str):
+ raise ValueError(f"Expected user to be a string but got {user!r}")
+ get_commit_datetimes_by_repo_period_intrinsic(
+ client, org, repo, user, since, until
+ )
+ get_pr_datetimes_by_repo_period_intrinsic(
+ client, org, repo, user, since, until
+ )
+ get_loc_stats_by_repo_period_intrinsic(
+ client, org, repo, user, since, until
+ )
+ count += 1
+ elapsed = time.time() - start
+ _LOG.info(
+ "Prefetched %d user-repo combos in %.2f seconds for period %s to %s.",
+ count,
+ elapsed,
+ period[0],
+ period[1],
+ )
+
+
+def collect_all_metrics(
+ client,
+ org: str,
+ repos: List[str],
+ users: List[str],
+ period: Tuple[datetime.datetime, datetime.datetime],
+) -> pd.DataFrame:
+ """
+ Collect daily metrics for all user-repo combinations.
+
+ :param client: authenticated PyGithub client
+ :param org: github org name
+ :param repos: repository names
+ :param users: github usernames
+ :param period: start and end datetime
+ :return: concatenated data with date, commits, prs, additions,
+ deletions, repo, user
+ """
+ combined_frames: List[pd.DataFrame] = []
+ for repo in repos:
+ # Ensure repo is a string.
+ if not isinstance(repo, str):
+ raise ValueError(f"Expected repo to be a string but got {repo!r}")
+ for user in users:
+ # Ensure user is a string.
+ if not isinstance(user, str):
+ raise ValueError(f"Expected user to be a string but got {user!r}")
+ # Build each metric DataFrame.
+ df_c = build_daily_commit_df(client, org, repo, user, period)
+ df_p = build_daily_pr_df(client, org, repo, user, period)
+ df_l = build_daily_loc_df(client, org, repo, user, period)
+ # Merge on date, repo, and user.
+ df = df_c.merge(df_p, on=["date", "repo", "user"], how="inner").merge(
+ df_l, on=["date", "repo", "user"], how="inner"
+ )
+ combined_frames.append(df)
+ # Concatenate all DataFrames or return empty.
+ combined = (
+ pd.concat(combined_frames, ignore_index=True)
+ if combined_frames
+ else pd.DataFrame()
+ )
+ return combined
+
+
+# Separate summary functions for user-repo and repo-user metrics for clarity.
+def summarize_user_metrics_for_repo(
+ combined: pd.DataFrame, repo: str
+) -> pd.DataFrame:
+ """
+ Summarize total commits, PRs, and LOC per user in a specific repository.
+
+ :param combined: data with all metrics
+ :param repo: repository name
+ :return: data with columns user, commits, prs, additions, deletions
+ """
+ df = combined[combined["repo"] == repo].copy()
+ df["additions"] = df["additions"].str.replace("+", "").astype(int)
+ df["deletions"] = df["deletions"].str.replace("-", "").astype(int)
+ summary = (
+ df.groupby("user")
+ .agg(
+ commits=pd.NamedAgg(column="commits", aggfunc="sum"),
+ prs=pd.NamedAgg(column="prs", aggfunc="sum"),
+ additions=pd.NamedAgg(column="additions", aggfunc="sum"),
+ deletions=pd.NamedAgg(column="deletions", aggfunc="sum"),
+ )
+ .reset_index()
+ )
+ return summary
+
+
+def summarize_repo_metrics_for_user(
+ combined: pd.DataFrame, user: str
+) -> pd.DataFrame:
+ """
+ Summarize total commits, PRs, and LOC per repository for a specific user.
+
+ :param combined: data with all metrics
+ :param user: GitHub username
+ :return: data with columns repo, commits, prs, additions, deletions
+ """
+ df = combined[combined["user"] == user].copy()
+ df["additions"] = df["additions"].str.replace("+", "").astype(int)
+ df["deletions"] = df["deletions"].str.replace("-", "").astype(int)
+ summary = (
+ df.groupby("repo")
+ .agg(
+ commits=pd.NamedAgg(column="commits", aggfunc="sum"),
+ prs=pd.NamedAgg(column="prs", aggfunc="sum"),
+ additions=pd.NamedAgg(column="additions", aggfunc="sum"),
+ deletions=pd.NamedAgg(column="deletions", aggfunc="sum"),
+ )
+ .reset_index()
+ )
+ return summary
+
+
+def plot_metrics_by_user(
+ summary: pd.DataFrame, repo: str, metrics: Optional[List[str]] = None
+) -> None:
+ """
+ Plot specified metrics for users in a single repo as grouped bar chart.
+
+ :param summary: data with summary from `compare_user_repo_summary`
+ :param repo: repository name
+ :param metrics: metrics to plot (commits, prs, additions, deletions)
+ """
+ # Determine which metrics to plot.
+ available = ["commits", "prs", "additions", "deletions"]
+ to_plot = metrics if metrics else available
+ # Validate metrics.
+ for m in to_plot:
+ if m not in available:
+ raise ValueError(f"Unsupported metric '{m}'")
+ x = list(range(len(to_plot)))
+ n_users = len(summary)
+ width = 0.8 / n_users if n_users else 0.8
+ fig, ax = plt.subplots()
+ # Plot bars and annotate counts.
+ for idx, user in enumerate(summary["user"]):
+ values = (
+ summary.loc[summary["user"] == user, to_plot]
+ .astype(int)
+ .iloc[0]
+ .tolist()
+ )
+ positions = [i + idx * width for i in x]
+ bars = ax.bar(positions, values, width=width, label=user)
+ for b in bars:
+ ax.text(
+ b.get_x() + b.get_width() / 2,
+ b.get_height(),
+ str(int(b.get_height())),
+ ha="center",
+ va="bottom",
+ )
+ # Center tick labels under bar groups.
+ ax.set_xticks([i + width * (n_users - 1) / 2 for i in x])
+ ax.set_xticklabels([m.capitalize() for m in to_plot])
+ ax.set_ylabel("Count")
+ # Update title format per user request.
+ ax.set_title(f"Metric comparison for {repo} Repo")
+ ax.legend()
+ plt.tight_layout()
+ plt.show()
+
+
+def plot_metrics_by_repo(
+ summary: pd.DataFrame, user: str, metrics: Optional[List[str]] = None
+) -> None:
+ """
+ Plot specified metrics for repos for a single user as grouped bar chart.
+
+ :param summary: data with summary from `compare_user_across_repos_summary`
+ :param user: github username
+ :param metrics: metrics to plot (commits, prs, additions, deletions)
+ """
+ # Determine which metrics to plot.
+ available = ["commits", "prs", "additions", "deletions"]
+ to_plot = metrics if metrics else available
+ # Validate metrics.
+ for m in to_plot:
+ if m not in available:
+ raise ValueError(f"Unsupported metric '{m}'")
+ x = list(range(len(to_plot)))
+ n_repos = len(summary)
+ width = 0.8 / n_repos if n_repos else 0.8
+ fig, ax = plt.subplots()
+ # Plot bars and annotate counts.
+ for idx, repo in enumerate(summary["repo"]):
+ values = (
+ summary.loc[summary["repo"] == repo, to_plot]
+ .astype(int)
+ .iloc[0]
+ .tolist()
+ )
+ positions = [i + idx * width for i in x]
+ bars = ax.bar(positions, values, width=width, label=repo)
+ for b in bars:
+ ax.text(
+ b.get_x() + b.get_width() / 2,
+ b.get_height(),
+ str(int(b.get_height())),
+ ha="center",
+ va="bottom",
+ )
+ # Center tick labels under bar groups.
+ ax.set_xticks([i + width * (n_repos - 1) / 2 for i in x])
+ ax.set_xticklabels([m.capitalize() for m in to_plot])
+ ax.set_ylabel("Count")
+ # Update title format per user request.
+ ax.set_title(f"Metric comparison for {user} across repos")
+ ax.legend()
+ plt.tight_layout()
+ plt.show()
diff --git a/tutorial_github_causify_style/github_utils_test.ipynb b/tutorial_github_causify_style/github_utils_test.ipynb
new file mode 100644
index 0000000000..744cc7f8be
--- /dev/null
+++ b/tutorial_github_causify_style/github_utils_test.ipynb
@@ -0,0 +1,688 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "CONTENTS:\n",
+ "- [Github API to understand user Contribution](#github-api-to-understand-user-contribution)\n",
+ " - [These numbers come straight from the upstream repo via the REST API, so they only include commits and PRs where you\u2019re the author or the committer on that repo. They **do not** pick up any work you did in a fork (or the individual commits squashed into a single merge), which is why they\u2019ll always undercount what GitHub Insights shows for your overall contributions.](#these-numbers-come-straight-from-the-upstream-repo-via-the-rest-api,-so-they-only-include-commits-and-prs-where-you\u2019re-the-author-or-the-committer-on-that-repo.-they-**do-not**-pick-up-any-work-you-did-in-a-fork-(or-the-individual-commits-squashed-into-a-single-merge),-which-is-why-they\u2019ll-always-undercount-what-github-insights-shows-for-your-overall-contributions.)\n",
+ " - [Set your Github PAT](#set-your-github-pat)\n",
+ " - [Pre-feth all the data you need in cache](#pre-feth-all-the-data-you-need-in-cache)\n",
+ " - [Query extraction takes time, so prefetch all data in cache for all the users, repos and time frames you need. once in cache there are several utility functions to help understand the user contribution. Following is the data we will fetch for users in multiple repos for the given period](#query-extraction-takes-time,-so-prefetch-all-data-in-cache-for-all-the-users,-repos-and-time-frames-you-need.-once-in-cache-there-are-several-utility-functions-to-help-understand-the-user-contribution.-following-is-the-data-we-will-fetch-for-users-in-multiple-repos-for-the-given-period)\n",
+ " - [Combine the data for statistics and visualizations](#combine-the-data-for-statistics-and-visualizations)\n",
+ " - [Compare users on a repo based on `commits`, `prs`, `additions` and `deletions`](#compare-users-on-a-repo-based-on-`commits`,-`prs`,-`additions`-and-`deletions`)\n",
+ " - [See stats of a user on multiple repos based on `commits`, `prs`, `additions` and `deletions`](#see-stats-of-a-user-on-multiple-repos-based-on-`commits`,-`prs`,-`additions`-and-`deletions`)\n",
+ " - [There are many more helper funcs to see and compare statistics. Look at github_utils for more info -> `tutorial_github_causify_style/github_utils.py`](#there-are-many-more-helper-funcs-to-see-and-compare-statistics.-look-at-github_utils-for-more-info-->-`tutorial_github_causify_style/github_utils.py`)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bdfbc31-a6d6-431e-b0ed-bdc69b8eec25",
+ "metadata": {},
+ "source": [
+ "\n",
+ "# Github API to understand user Contribution"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "923ef379-8424-46df-9b60-29d35a63a331",
+ "metadata": {},
+ "source": [
+ "\n",
+ "### These numbers come straight from the upstream repo via the REST API, so they only include commits and PRs where you\u2019re the author or the committer on that repo. They **do not** pick up any work you did in a fork (or the individual commits squashed into a single merge), which is why they\u2019ll always undercount what GitHub Insights shows for your overall contributions.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "442cd592-3137-4d73-a113-655bf8dfd3fe",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!sudo /bin/bash -c \"(source /venv/bin/activate; pip install --quiet jupyterlab-vim PyGithub)\"\n",
+ "!jupyter labextension enable"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "268ddc35-9bb4-4e0a-b7f4-a8409baf9904",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "import os\n",
+ "import datetime\n",
+ "import time\n",
+ "import importlib \n",
+ "\n",
+ "import github_utils\n",
+ "import helpers.hcache_simple as hcache\n",
+ "import helpers.hcache_simple as hcacsimp\n",
+ "from github import Github\n",
+ "\n",
+ "# Enable logging.\n",
+ "logging.basicConfig(level=logging.INFO)\n",
+ "_LOG = logging.getLogger(__name__)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "9c25ee1d-620b-485e-b98c-769c7fff8ab4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "importlib.reload(github_utils)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6afd498b-8453-42e1-852c-ac093f8e0bfd",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## Set your Github PAT"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "3220998c-1261-418f-859b-b20bb9a6cb61",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Set your GitHub access token here.\n",
+ "os.environ[\"GITHUB_ACCESS_TOKEN\"] = \"YOUR_GIT_PAT\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "03983a64-78a2-49c3-9163-815cf0ef3a77",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "access_token = os.getenv(\"GITHUB_ACCESS_TOKEN\")\n",
+ "if not access_token:\n",
+ " _LOG.error(\"GITHUB_ACCESS_TOKEN not set. Exiting.\")\n",
+ " raise ValueError(\"Set GITHUB_ACCESS_TOKEN environment variable\")\n",
+ "\n",
+ "client = github_utils.GitHubAPI(access_token=access_token).get_client()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4cc7efd4-af91-44e8-9e3c-2bdbc8440c9d",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## Pre-feth all the data you need in cache "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7772ca8-b716-412a-8526-74977f0c3ae5",
+ "metadata": {},
+ "source": [
+ "\n",
+ "### Query extraction takes time, so prefetch all data in cache for all the users, repos and time frames you need. once in cache there are several utility functions to help understand the user contribution. Following is the data we will fetch for users in multiple repos for the given period \n",
+ "- Prs opened in the repo\n",
+ "- Commits done\n",
+ "- LOC [additions and deletions]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "0002b5e0-6975-4058-b9cd-b06676c89d38",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "INFO:github_utils:Starting prefetch for repo helpers.\n",
+ "INFO:github_utils:Fetched 20 commits for causify-ai/helpers user=Shaunak01.\n",
+ "INFO:github_utils:Found 24 PRs for causify-ai/helpers user=Shaunak01.\n",
+ "INFO:github_utils:Fetched LOC stats for causify-ai/helpers user=Shaunak01 entries=20.\n",
+ "INFO:github_utils:Starting prefetch for repo tutorials.\n",
+ "INFO:github_utils:Fetched 1 commits for causify-ai/tutorials user=Shaunak01.\n",
+ "INFO:github_utils:Found 3 PRs for causify-ai/tutorials user=Shaunak01.\n",
+ "INFO:github_utils:Fetched LOC stats for causify-ai/tutorials user=Shaunak01 entries=1.\n",
+ "INFO:github_utils:Starting prefetch for repo cmamp.\n",
+ "INFO:github_utils:Fetched 23 commits for causify-ai/cmamp user=Shaunak01.\n",
+ "INFO:github_utils:Found 28 PRs for causify-ai/cmamp user=Shaunak01.\n",
+ "INFO:github_utils:Fetched LOC stats for causify-ai/cmamp user=Shaunak01 entries=23.\n",
+ "INFO:github_utils:Prefetched 9 user-repo combos in 62.79 seconds for period 2025-01-01 00:00:00+00:00 to 2025-05-24 00:00:00+00:00.\n"
+ ]
+ }
+ ],
+ "source": [
+ "github_utils.prefetch_periodic_user_repo_data(\n",
+ " client,\n",
+ " org=\"causify-ai\",\n",
+ " repos=[\"helpers\",\"tutorials\",\"cmamp\"],\n",
+ " users=[\"tkpratardan\",\"Prahar08modi\",\"Shaunak01\"],\n",
+ " period=(\n",
+ " datetime.datetime(2025, 1, 1, tzinfo=datetime.timezone.utc),\n",
+ " datetime.datetime(2025, 5, 24, tzinfo=datetime.timezone.utc),\n",
+ " ),\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4e6e1277-32f0-4fca-9c62-6f29eebb6a44",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## Combine the data for statistics and visualizations"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "d03e07fc-37f6-4d69-8c16-2bc4296d0334",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144 (no data).\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144 (no data).\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily PR DataFrame rows=144.\n",
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily LOC DataFrame rows=144.\n"
+ ]
+ }
+ ],
+ "source": [
+ "combined = github_utils.collect_all_metrics(\n",
+ " client, org=\"causify-ai\",\n",
+ " repos=[\"helpers\",\"tutorials\",\"cmamp\"],\n",
+ " users=[\"Prahar08modi\",\"tkpratardan\",\"Shaunak01\"],\n",
+ " period=(datetime.datetime(2025,1,1, tzinfo=datetime.timezone.utc),\n",
+ " datetime.datetime(2025,5,24, tzinfo=datetime.timezone.utc)),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb0aa61c-60f4-4b85-841a-623e3d069913",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## Compare users on a repo based on `commits`, `prs`, `additions` and `deletions`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "62bfd155-8e08-4ddb-82a2-3ec9d9a2c9ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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pKioKF29elXvv/++GjdurF27dlkDYqYnn3xSwcHBevPNN7ME5hvNnj1bNWrU0GOPPaZixYrpm2++0cCBA5WRkaFBgwbl2O+jjz7S0KFD1blzZz3//PO6du2afvvtN23duvWm/73kJPMfB6VKlbKuu3Llipo2baqTJ0+qf//+qlChgjZt2qTRo0fr9OnTWR6G+eSTT3Tp0iUNGjRI165d04wZM9SiRQvt2bPH+vdCXt9HQJJkADAMwzDmzZtnSDK2b99uzJw503B3dzeuXLliGIZhPPnkk0bz5s0NwzCMihUrGu3atbP2+/nnnw1Jxueff24zXnR0dJb1NWrUMJo2bZrjvps0aWL8/fff2W47evSoYRiGkZiYaLi7uxthYWHG1atXbdpmZGTc9Bh79OhhODg4GNu3b8+yLbPvsGHDDEnGzz//bN126dIlIzAw0AgICDDS09MNwzCM9evXG5KMmjVrGmlpada23bp1MywWi9GmTRub8cPDw42KFSvarJNkSDJ27NhhXXfs2DHDxcXF6NSpk3Vd5udwo82bNxuSjE8++cS6Li/v4/Lly62fd05WrFhhSDJef/11m/WdO3c2LBaLcfjwYZtjcXJysln366+/GpKM999/P8d93Nh/0KBBNuvy+lkEBQVl+17927lz5wxJxvjx47Nsa9q0abbf0Z49e9p8fjcbo27duoaPj49x4cIF67pff/3VcHBwMHr06GFdN378eEOS0a1btyxjZG67UXbHFhkZaQQFBd30GDp06GDUqFEjS99bOXr0qCHJmDBhgnHu3DkjISHB+Pnnn40GDRoYkoylS5da206cONEoWbKk8ccff9iMMWrUKMPR0dGIj4+3GdPV1dU4ceKEtd3WrVsNScbw4cOt63L7PgI34lIskI0uXbro6tWrWrVqlS5duqRVq1bl+C/7pUuXytPTUy1bttT58+etr9DQULm5uWn9+vW53m+/fv3k6Oh40zZr167VpUuXNGrUqCz3IN3s/rGMjAytWLFC7du3V/369bNsz+y7evVqNWzY0HpJTJLc3Nz03HPPKS4uTvv27bPp16NHDxUvXty6HBYWJsMwslzSDAsL0/Hjx7PcuxgeHq7Q0FDrcoUKFdShQwetWbNG6enpkiRXV1fr9uvXr+vChQuqXLmyvLy8tGvXrizHkpv3MfN+tlWrVun69evZtlm9erUcHR01dOhQm/UvvPCCDMPQd999Z7M+IiJClSpVsi7Xrl1bHh4e+vPPP29aS07y+ln07NnT5r2yh9OnTys2Nla9evVS6dKlretr166tli1bavXq1Vn6/M///E+uxr7x2JKSknT+/Hk1bdpUf/75p5KSknLs5+XlpRMnTmj79u15OJL/M378eHl7e8vPz08PPfSQ9u/frylTpqhz587WNkuXLtVDDz2kUqVK2fw9EBERofT09Cy3F3Ts2FH33Xefdblhw4YKCwuzvj+38z4CEvfYAdny9vZWRESEFi5cqGXLlik9Pd3mL/EbHTp0SElJSfLx8ZG3t7fNKyUlRWfPns31fgMDA2/ZJvO+nszLlLl17tw5JScn37LfsWPHVLVq1Szrq1evbt1+owoVKtgse3p6SpL8/f2zrM/IyMjyP+Dg4OAs+6pSpYquXLmic+fOSZKuXr2qcePGWe9dKlu2rLy9vZWYmJjt/9Bz8z42bdpUTzzxhCZMmKCyZcuqQ4cOmjdvns19gMeOHVP58uXl7u5u0ze374X0z+W6G++1zIu8fha5Oe67LbOmnOo+f/58lsvjua1748aNioiIsN5v5u3trVdeeUWSbhrsXn75Zbm5ualhw4YKDg7WoEGDtHHjxtwekp577jmtXbtW33zzjYYPH66rV69a/9GR6dChQ4qOjs7yd0BERIQkZfl7IKfvfeZl3tt5HwGJe+yAHD399NPq16+fEhIS1KZNmxyfWMzIyJCPj48+//zzbLdn3mSeG/Y+23I7cjozltN64yb3UOVkyJAhmjdvnoYNG6bw8HB5enrKYrHoqaeeyvbJz9y8jxaLRV9++aW2bNmib775RmvWrFGfPn00ZcoUbdmyRW5ubnmuMz+P+Xbkx/cn80GOf/t3kMlPuan7yJEjeuSRR1StWjVNnTpV/v7+cnJy0urVqzVt2rSbPgFcvXp1HTx4UKtWrVJ0dLS++uorffDBBxo3bpwmTJhwy30HBwdbA9qjjz4qR0dHjRo1Ss2bN7ee/c7IyFDLli310ksvZTtGlSpVbrkfID8Q7IAcdOrUSf3799eWLVu0ZMmSHNtVqlRJ69atU+PGjW/5P6j8mGoj81Lf3r17Vbly5Vz38/b2loeHR7ZP3t2oYsWKOnjwYJb1Bw4csG7PT4cOHcqy7o8//lCJEiWsofjLL79Uz549NWXKFGuba9euKTEx8Y73/+CDD+rBBx/UG2+8oYULF6p79+5avHixnn32WVWsWFHr1q3TpUuXbM7a3a334t/u1mdxs+9hqVKlsr10/O+zgzmNkVlTTnWXLVtWJUuWzEu5kqRvvvlGqampWrlypc2Z0dze6lCyZEl17dpVXbt2VVpamh5//HG98cYbGj16dJ6nVXn11Vf10UcfacyYMdannitVqqSUlBRrALyVnL73mQ9E3K33EebHpVggB25ubpo9e7aioqLUvn37HNt16dJF6enpmjhxYpZtf//9t034KFmy5B2HkVatWsnd3V2TJk3StWvXbLbd7MyQg4ODOnbsqG+++UY7duzIsj2zb9u2bbVt2zabmfUvX76sDz/8UAEBAQoJCbmj+v9t8+bNNvfJHT9+XF9//bVatWplPQPm6OiY5djef//9OzqL9Ndff2UZs27dupJkvRzbtm1bpaena+bMmTbtpk2bJovFYn1q+m65W59F5lPE2X0XK1WqpAMHDlgvg0vSr7/+muXSZU5jlCtXTnXr1tWCBQtstu3du1fff/+92rZte1s1Z34XbvzMkpKSNG/evFv2vXDhgs2yk5OTQkJCZBhGjvdX3oyXl5f69++vNWvWKDY2VtI/fw9s3rxZa9asydI+MTExy72lK1as0MmTJ63L27Zt09atW63fqbv1PsL8OGMH3ETPnj1v2aZp06bq37+/Jk2apNjYWLVq1UrFixfXoUOHtHTpUs2YMcN6f15oaKhmz56t119/XZUrV5aPj49atGiRp5o8PDw0bdo0Pfvss2rQoIF1/q9ff/1VV65c0YIFC3Ls++abb+r7779X06ZN9dxzz6l69eo6ffq0li5dql9++UVeXl4aNWqUdaqXoUOHqnTp0lqwYIGOHj2qr776Sg4O+fvvwZo1ayoyMtJmuhNJNpfIHn30UX366afy9PRUSEiINm/erHXr1uU4hUhuLFiwQB988IE6deqkSpUq6dKlS/roo4/k4eFh/Z9m+/bt1bx5c7366quKi4tTnTp19P333+vrr7/WsGHDbB6UuBvu1mfh6uqqkJAQLVmyRFWqVFHp0qVVs2ZN1axZU3369NHUqVMVGRmpvn376uzZs5ozZ45q1KhhMy/ezcaYPHmy2rRpo/DwcPXt29c6TYenp6fNXHd50apVKzk5Oal9+/bq37+/UlJS9NFHH8nHx0enT5++ZV8/Pz81btxYvr6+2r9/v2bOnKl27dpluX8yt55//nlNnz5db731lhYvXqwXX3xRK1eu1KOPPqpevXopNDRUly9f1p49e/Tll18qLi5OZcuWtfavXLmymjRpogEDBig1NVXTp09XmTJlbC7l3o33EfcAOz2NCxQ6N053cjP/nu4k04cffmiEhoYarq6uhru7u1GrVi3jpZdeMk6dOmVtk5CQYLRr185wd3c3JFmnZLjZvv89TUemlStXGo0aNTJcXV0NDw8Po2HDhsaiRYtueZzHjh0zevToYXh7exvOzs5GUFCQMWjQICM1NdXa5siRI0bnzp0NLy8vw8XFxWjYsKGxatUqm3Eyp9i4ccqHmx1L5vQV586ds67T/5/i47PPPjOCg4MNZ2dno169esb69ett+v71119G7969jbJlyxpubm5GZGSkceDAAaNixYpGz549b7nv7N7HXbt2Gd26dTMqVKhgODs7Gz4+Psajjz5qM/WKYfwzvcjw4cON8uXLG8WLFzeCg4ONyZMnZ5laRtlMV2IYRpYac5JT/zv5LG5m06ZNRmhoqOHk5JRl2pLPPvvMCAoKMpycnIy6desaa9asyTLdya3GWLdundG4cWPr97N9+/bGvn37bPpn953497YbrVy50qhdu7bh4uJiBAQEGG+//bYxd+7cLP99/Hu6k//+97/Gww8/bJQpU8ZwdnY2KlWqZLz44otGUlLSTd+jzKlJJk+enO32Xr16GY6OjtYpbi5dumSMHj3aqFy5suHk5GSULVvWaNSokfHuu+9apwS6ccwpU6YY/v7+hrOzs/HQQw8Zv/76a5Z95OZ9BG5kMYwCuqsXAP7FYrFo0KBBWS51AmYVFxenwMBATZ48WSNHjrR3OTAh7rEDAAAwCYIdAACASRDsAAAATIJ77AAAAEyCM3YAAAAmQbADAAAwCSYozkZGRoZOnTold3f3fPkJKAAAgNtlGIYuXbqk8uXL33JicoJdNk6dOiV/f397lwEAAGB1/Phx3X///TdtQ7DLRuZPzBw/flweHh52rgYAANzLkpOT5e/vn6ufwCPYZSPz8quHhwfBDgAAFAq5uT2MhycAAABMgmAHAABgEgQ7AAAAk+AeOwAA7lB6erquX79u7zJQRBUvXlyOjo75MhbBDgDuwKRJk7Rs2TIdOHBArq6uatSokd5++21VrVrV2uba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/15dunRR//79lZ6ervDwcK1evdqmX0ZGhubOnSt3d3eFhISoefPmOnjwoFavXi0HBwdVrVpVb7/9ttavX6+wsDDFxMRoz549Onr0qPz9/SVJn3zyiWrUqKHt27erQYMGmj59uvr27au+fftKkl5//XWtW7fOLlcKC81Tsfk1/1Pm+n//BuPN+qSmpio5OdnmBQCAma1atUpubm5ycXFRmzZt1LVrV0VFRUmSatWqZRPqpH9OtrRv314VKlSQu7u7Nbz9+2xb7dq1rX/O/HmszEu2KSkpGjlypKpXry4vLy+5ublp//79Wca48cxcbiUkJKhfv37q2bOntm/frg0bNsjJyUmdO3e2eWghICBA7u7u1mVfX1+FhITIwcHBZl1mzfv375e/v7811ElSSEiIvLy8tH//fmubsLAwm3rs9XBUoTljZ8/5nyZNmqQJEyYU+H6BQivK094VAFlFJdm7AlNp3ry5Zs+eLScnJ5UvX97madjM3znOdPnyZUVGRioyMlKff/65vL29FR8fr8jIyCwPV9x42TNz0t2MjAxJ0siRI7V27Vq9++67qly5slxdXdW5c+csY/x7/35+flnu5/v777918eJF620Ns2bNkqenp9555x1rm88++0z+/v7aunWr9SrfjfVl1pjdusyai5pCccYuP+d/ylz/75sab9Zn9OjRSkpKsr6OHz9+B0cDAEDhV7JkSVWuXFkVKlS45RQnBw4c0IULF/TWW2/poYceUrVq1bJ9cOJWNm7cqF69eqlTp06qVauW/Pz8FBcXd8t+4eHhSkxMtN6DL0k//PCDMjIyrGfKrly5YnPWTZL1N1fvJKRVr15dx48ft8kG+/btU2JiokJCQqxtMu/Jy5TTswB3m12DnWEYGjx4sJYvX64ffvjhpvM/ZbrV/E+BgYHy8/Oz6ZOcnKytW7fm2MfZ2VkeHh42LwAA8I8KFSrIyclJ77//vv7880+tXLlSEydOzPM4wcHBWrZsmWJjY/Xrr7/q6aefzlXoql69ulq3bq1+/fpp27Zt2rhxowYPHqynnnpK5cuXlyS1a9dO27dv12uvvaZDhw5p165d6t27typWrKh69erludZMERERqlWrlrp3765du3Zp27Zt6tGjh5o2bWq9ZPz8889r7ty5mjdvnv744w/rXHr2YNdgl1/zP1WrVk3Lly+X9M/p02HDhun1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Qg0bNrSuDw4O1jvvvGNdfuWVV1SpUiVNmTJFklS1alXt2bNHb7/9dp7Hrl27tsaPH2/dz8yZMxUTE2NzfIUNwQ4AAEiSWrZsqYYNG2rJkiVydHTMsj08PNz652LFiql+/frav3+/TZv69evbLKekpCgqKkrffvutTp8+rb///ltXr161nrHLSXp6ut5880198cUXOnnypNLS0pSamqoSJUrYtAsNDbVZ3r9/v8LCwnKsOy9j165d22a5XLlyOnv27E3rtjeCHQAAkCS1a9dOX331lfbt26datW7vyd6SJUvaLI8cOVJr167Vu+++q8qVK8vV1VWdO3e+5YMOkydP1owZMzR9+nTVqlVLJUuW1LBhw7L0+/f+ciO3YxcvXtxm2WKxKCMjI8/7K0h2vcfup59+Uvv27VW+fHlZLBatWLHCZnvmTZT/fk2ePDnHMaOiorK0r1at2l0+EgAAig4nJyelp6dnWf/WW2+pZ8+eeuSRR7Rv374s27ds2WL9899//62dO3eqevXqN93Xxo0b1atXL3Xq1Em1atWSn59flocZsqtn48aN6tChg5555hnVqVNHQUFB+uOPP255bNWrV89yr9yNdd/J2EWBXYPd5cuXVadOHc2aNSvb7Zk3UWa+5s6dK4vFYr2+n5MaNWrY9Pvll1/uRvkAABRJAQEB2rp1q+Li4nT+/Hmbs1DvvvuuunfvrhYtWljvvcs0a9YsLV++XAcOHNCgQYP0119/qU+fPjfdV3BwsJYtW6bY2Fj9+uuvevrpp7Oc9QoICNBPP/2kkydP6vz589Z+a9eu1aZNm7R//371799fZ86cueWx/c///I8OHTqkF198UQcPHtTChQs1f/78LDXdzthFgV2DXZs2bfT666+rU6dO2W738/OzeX399ddq3ry5goKCbjpusWLFbPqVLVv2bpQPAECRNHLkSDk6OiokJETe3t5Z7nebNm2aunTpohYtWticyXrrrbf01ltvqU6dOvrll1+0cuXKW/4/durUqSpVqpQaNWqk9u3bKzIyUg888IBNm9dee01xcXGqVKmSvL29JUljxozRAw88oMjISDVr1kx+fn7q2LHjLY+tQoUK+uqrr7RixQrVqVNHc+bM0ZtvvmnT5nbHLgoshmEY9i5C+uey6/Lly3N8Y8+cOaP7779fCxYs0NNPP53jOFFRUZo8ebI8PT3l4uKi8PBwTZo0SRUqVMh1LcnJyfL09FRSUpI8PDzyeihA0Rflae8KgKyikuxdgY1r167p6NGjCgwMlIuLi73Luavi4uIUGBio3bt3q27duvYux5Ru9n3KSy4pMg9PLFiwQO7u7nr88cdv2i4sLEzz589X1apVdfr0aU2YMEEPPfSQ9u7dK3d392z7pKamKjU11bqcnJycr7UDAAAUhCIT7ObOnavu3bvf8l9Fbdq0sf65du3aCgsLU8WKFfXFF1+ob9++2faZNGmSJkyYkK/1AgAAFLQi8csTP//8sw4ePKhnn302z329vLxUpUoVHT58OMc2o0ePVlJSkvV1/PjxOykXAABTCQgIkGEYXIYtAopEsPv4448VGhpqM3N1bqWkpOjIkSMqV65cjm2cnZ3l4eFh8wIAAChq7BrsUlJSFBsbq9jYWEnS0aNHFRsba/N0TnJyspYuXZrj2bpHHnlEM2fOtC6PHDlSGzZsUFxcnDZt2qROnTrJ0dFR3bp1u6vHAgAAYG92vcdux44dat68uXV5xIgRkqSePXta55xZvHixDMPIMZgdOXLEOueNJJ04cULdunXThQsX5O3trSZNmmjLli3Wx6cBAMhPhf2XCFA05Nf3qNBMd1KYMN0J7nlMd4LCqJBNd5KRkaFDhw7J0dFR3t7ecnJyksVisXdZKGIMw1BaWprOnTun9PR0BQcHy8HB9oKqKac7AQCgMHFwcFBgYKBOnz6tU6dO2bscFHElSpRQhQoVsoS6vCLYAQBwm5ycnFShQgX9/fff2f72KpAbjo6OKlasWL6c8SXYAQBwBywWi4oXL67ixYvbuxSgaEx3AgAAgFsj2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJiEXYPdTz/9pPbt26t8+fKyWCxasWKFzfZevXrJYrHYvFq3bn3LcWfNmqWAgAC5uLgoLCxM27Ztu0tHAAAAUHjYNdhdvnxZderU0axZs3Js07p1a50+fdr6WrRo0U3HXLJkiUaMGKHx48dr165dqlOnjiIjI3X27Nn8Lh8AAKBQKWbPnbdp00Zt2rS5aRtnZ2f5+fnlesypU6eqX79+6t27tyRpzpw5+vbbbzV37lyNGjXqjuoFAAAozAr9PXY//vijfHx8VLVqVQ0YMEAXLlzIsW1aWpp27typiIgI6zoHBwdFRERo8+bNBVEuAACA3dj1jN2ttG7dWo8//rgCAwN15MgRvfLKK2rTpo02b94sR0fHLO3Pnz+v9PR0+fr62qz39fXVgQMHctxPamqqUlNTrcvJycn5dxAAAAAFpFAHu6eeesr651q1aql27dqqVKmSfvzxRz3yyCP5tp9JkyZpwoQJ+TYeAACAPRT6S7E3CgoKUtmyZXX48OFst5ctW1aOjo46c+aMzfozZ87c9D690aNHKykpyfo6fvx4vtYNAABQEIpUsDtx4oQuXLigcuXKZbvdyclJoaGhiomJsa7LyMhQTEyMwsPDcxzX2dlZHh4eNi8AAICixq7BLiUlRbGxsYqNjZUkHT16VLGxsYqPj1dKSopefPFFbdmyRXFxcYqJiVGHDh1UuXJlRUZGWsd45JFHNHPmTOvyiBEj9NFHH2nBggXav3+/BgwYoMuXL1ufkgUAADAru95jt2PHDjVv3ty6PGLECElSz549NXv2bP32229asGCBEhMTVb58ebVq1UoTJ06Us7Oztc+RI0d0/vx563LXrl117tw5jRs3TgkJCapbt66io6OzPFABAABgNhbDMAx7F1HYJCcny9PTU0lJSVyWxb0pytPeFQBZRSXZuwLALvKSS4rUPXYAAADIGcEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEnYNdj99NNPat++vcqXLy+LxaIVK1ZYt12/fl0vv/yyatWqpZIlS6p8+fLq0aOHTp06ddMxo6KiZLFYbF7VqlW7y0cCAABgf3YNdpcvX1adOnU0a9asLNuuXLmiXbt2aezYsdq1a5eWLVumgwcP6rHHHrvluDVq1NDp06etr19++eVulA8AAFCoFLPnztu0aaM2bdpku83T01Nr1661WTdz5kw1bNhQ8fHxqlChQo7jFitWTH5+fvlaKwAAQGFXpO6xS0pKksVikZeX103bHTp0SOXLl1dQUJC6d++u+Pj4gikQAADAjux6xi4vrl27ppdfflndunWTh4dHju3CwsI0f/58Va1aVadPn9aECRP00EMPae/evXJ3d8+2T2pqqlJTU63LycnJ+V4/AADA3VYkgt3169fVpUsXGYah2bNn37TtjZd2a9eurbCwMFWsWFFffPGF+vbtm22fSZMmacKECflaMwAAQEEr9JdiM0PdsWPHtHbt2puercuOl5eXqlSposOHD+fYZvTo0UpKSrK+jh8/fqdlAwAAFLhCHewyQ92hQ4e0bt06lSlTJs9jpKSk6MiRIypXrlyObZydneXh4WHzAgAAKGrsGuxSUlIUGxur2NhYSdLRo0cVGxur+Ph4Xb9+XZ07d9aOHTv0+eefKz09XQkJCUpISFBaWpp1jEceeUQzZ860Lo8cOVIbNmxQXFycNm3apE6dOsnR0VHdunUr6MMDAAAoUHa9x27Hjh1q3ry5dXnEiBGSpJ49eyoqKkorV66UJNWtW9em3/r169WsWTNJ0pEjR3T+/HnrthMnTqhbt266cOGCvL291aRJE23ZskXe3t5392AAAADszK7BrlmzZjIMI8ftN9uWKS4uzmZ58eLFd1oWAABAkVSo77EDAABA7hHsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkbivYBQUF6cKFC1nWJyYmKigo6I6LAgAAQN7dVrCLi4tTenp6lvWpqak6efLkHRcFAACAvCuWl8YrV660/nnNmjXy9PS0LqenpysmJkYBAQH5VhwAAAByL0/BrmPHjpIki8Winj172mwrXry4AgICNGXKlHwrDgAAALmXp2CXkZEhSQoMDNT27dtVtmzZu1IUAAAA8i5PwS7T0aNH87sOAAAA3KHbCnaSFBMTo5iYGJ09e9Z6Ji/T3Llz77gwAAAA5M1tBbsJEybotddeU/369VWuXDlZLJb8rgsAAAB5dFvBbs6cOZo/f77+85//5Hc9AAAAuE23NY9dWlqaGjVqlN+1AAAA4A7cVrB79tlntXDhwvyuBQAAAHfgti7FXrt2TR9++KHWrVun2rVrq3jx4jbbp06dmi/FAQAAIPduK9j99ttvqlu3riRp7969Ntt4kAIAAMA+bivYrV+/Pr/rAAAAwB26rXvsAAAAUPjc1hm75s2b3/SS6w8//HDbBQEAAOD23Fawy7y/LtP169cVGxurvXv3qmfPnvlRFwAAAPLotoLdtGnTsl0fFRWllJSUOyoIAAAAtydf77F75pln+J1YAAAAO8nXYLd582a5uLjk55AAAADIpdu6FPv444/bLBuGodOnT2vHjh0aO3ZsvhQGAACAvLmtYOfp6Wmz7ODgoKpVq+q1115Tq1at8qUwAAAA5M1tBbt58+bldx0AAAC4Q3d0j93OnTv12Wef6bPPPtPu3bvz3P+nn35S+/btVb58eVksFq1YscJmu2EYGjdunMqVKydXV1dFRETo0KFDtxx31qxZCggIkIuLi8LCwrRt27Y81wYAAFDU3FawO3v2rFq0aKEGDRpo6NChGjp0qEJDQ/XII4/o3LlzuR7n8uXLqlOnjmbNmpXt9nfeeUfvvfee5syZo61bt6pkyZKKjIzUtWvXchxzyZIlGjFihMaPH69du3apTp06ioyM1NmzZ/N8nAAAAEXJbQW7IUOG6NKlS/r999918eJFXbx4UXv37lVycrKGDh2a63HatGmj119/XZ06dcqyzTAMTZ8+XWPGjFGHDh1Uu3ZtffLJJzp16lSWM3s3mjp1qvr166fevXsrJCREc+bMUYkSJZiGBQAAmN5tBbvo6Gh98MEHql69unVdSEiIZs2ape+++y5fCjt69KgSEhIUERFhXefp6amwsDBt3rw52z5paWnauXOnTR8HBwdFRETk2AcAAMAsbuvhiYyMDBUvXjzL+uLFiysjI+OOi5KkhIQESZKvr6/Nel9fX+u2fzt//rzS09Oz7XPgwIEc95WamqrU1FTrcnJy8u2WDQAAYDe3dcauRYsWev7553Xq1CnrupMnT2r48OF65JFH8q24gjJp0iR5enpaX/7+/vYuCQAAIM9uK9jNnDlTycnJCggIUKVKlVSpUiUFBgYqOTlZ77//fr4U5ufnJ0k6c+aMzfozZ85Yt/1b2bJl5ejomKc+kjR69GglJSVZX8ePH7/D6gEAAArebV2K9ff3165du7Ru3TrrJc7q1avb3Nt2pwIDA+Xn56eYmBjVrVtX0j+XSLdu3aoBAwZk28fJyUmhoaGKiYlRx44dJf1z2TgmJkaDBw/OcV/Ozs5ydnbOt9oBAADsIU9n7H744QeFhIQoOTlZFotFLVu21JAhQzRkyBA1aNBANWrU0M8//5zr8VJSUhQbG6vY2FhJ/zwwERsbq/j4eFksFg0bNkyvv/66Vq5cqT179qhHjx4qX768NbRJ0iOPPKKZM2dal0eMGKGPPvpICxYs0P79+zVgwABdvnxZvXv3zsuhAgAAFDl5OmM3ffp09evXTx4eHlm2eXp6qn///po6daoeeuihXI23Y8cONW/e3Lo8YsQISVLPnj01f/58vfTSS7p8+bKee+45JSYmqkmTJoqOjpaLi4u1z5EjR3T+/HnrcteuXXXu3DmNGzdOCQkJqlu3rqKjo7M8UAEAAGA2FsMwjNw2rlixoqKjo22mObnRgQMH1KpVK8XHx+dbgfaQnJwsT09PJSUlZRtiAdOL8rx1G6CgRSXZuwLALvKSS/J0KfbMmTPZTnOSqVixYnn65QkAAADknzwFu/vuu0979+7Ncftvv/2mcuXK3XFRAAAAyLs8Bbu2bdtq7Nix2f5W69WrVzV+/Hg9+uij+VYcAAAAci9P99idOXNGDzzwgBwdHTV48GBVrVpV0j/31s2aNUvp6enatWtXkX9QgXvscM/jHjsURtxjh3tUXnJJnp6K9fX11aZNmzRgwACNHj1amZnQYrEoMjJSs2bNKvKhDgAAoKjK8wTFFStW1OrVq/XXX3/p8OHDMgxDwcHBKlWq1N2oDwAAALl0W788IUmlSpVSgwYN8rMWAAAA3IHb+q1YAAAAFD4EOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRDsAAAATIJgBwAAYBIEOwAAAJMg2AEAAJgEwQ4AAMAkCHYAAAAmQbADAAAwCYIdAACASRT6YBcQECCLxZLlNWjQoGzbz58/P0tbFxeXAq4aAACg4BWzdwG3sn37dqWnp1uX9+7dq5YtW+rJJ5/MsY+Hh4cOHjxoXbZYLHe1RgAAgMKg0Ac7b29vm+W33npLlSpVUtOmTXPsY7FY5Ofnd7dLAwAAKFQK/aXYG6Wlpemzzz5Tnz59bnoWLiUlRRUrVpS/v786dOig33///abjpqamKjk52eYFAABQ1BSpYLdixQolJiaqV69eObapWrWq5s6dq6+//lqfffaZMjIy1KhRI504cSLHPpMmTZKnp6f15e/vfxeqBwAAuLsshmEY9i4ityIjI+Xk5KRvvvkm132uX7+u6tWrq1u3bpo4cWK2bVJTU5WammpdTk5Olr+/v5KSkuTh4XHHdQNFTpSnvSsAsopKsncFgF0kJyfL09MzV7mk0N9jl+nYsWNat26dli1blqd+xYsXV7169XT48OEc2zg7O8vZ2flOSwQAALCrInMpdt68efLx8VG7du3y1C89PV179uxRuXLl7lJlAAAAhUORCHYZGRmaN2+eevbsqWLFbE8y9ujRQ6NHj7Yuv/baa/r+++/1559/ateuXXrmmWd07NgxPfvsswVdNgAAQIEqEpdi161bp/j4ePXp0yfLtvj4eDk4/F8+/euvv9SvXz8lJCSoVKlSCg0N1aZNmxQSElKQJQMAABS4IvXwREHJy02KgCnx8AQKIx6ewD0qL7mkSFyKBQAAwK0R7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAuEecPHlSzzzzjMqUKSNXV1fVqlVLO3bssHdZyEdF4rdiAQDAnfnrr7/UuHFjNW/eXN999528vb116NAhlSpVyt6lIR8R7AAAuAe8/fbb8vf317x586zrAgMD7VgR7gYuxQIAcA9YuXKl6tevryeffFI+Pj6qV6+ePvroI3uXhXxGsAMA4B7w559/avbs2QoODtaaNWs0YMAADR06VAsWLLB3achHXIoFAOAekJGRofr16+vNN9+UJNWrV0979+7VnDlz1LNnTztXh/zCGTsAAO4B5cqVU0hIiM266tWrKz4+3k4V4W4g2AEAcA9o3LixDh48aLPujz/+UMWKFe1UEe4Ggh0AAPeA4cOHa8uWLXrzzTd1+PBhLVy4UB9++KEGDRpk79KQjwh2AADcAxo0aKDly5dr0aJFqlmzpiZOnKjp06ere/fu9i4N+YiHJwAAuEc8+uijevTRR+1dBu4iztgBAACYBMEOAADAJLgUCwAoEmotqGXvEoBs7em5x94lWHHGDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEgQ7AAAAkyDYAQAAmATBDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEoU62EVFRclisdi8qlWrdtM+S5cuVbVq1eTi4qJatWpp9erVBVQtAACAfRXqYCdJNWrU0OnTp62vX375Jce2mzZtUrdu3dS3b1/t3r1bHTt2VMeOHbV3794CrBgAAMA+Cn2wK1asmPz8/KyvsmXL5th2xowZat26tV588UVVr15dEydO1AMPPKCZM2cWYMUAAAD2UeiD3aFDh1S+fHkFBQWpe/fuio+Pz7Ht5s2bFRERYbMuMjJSmzdvvuk+UlNTlZycbPMCAAAoagp1sAsLC9P8+fMVHR2t2bNn6+jRo3rooYd06dKlbNsnJCTI19fXZp2vr68SEhJuup9JkybJ09PT+vL398+3YwAAACgohTrYtWnTRk8++aRq166tyMhIrV69WomJifriiy/ydT+jR49WUlKS9XX8+PF8HR8AAKAgFLN3AXnh5eWlKlWq6PDhw9lu9/Pz05kzZ2zWnTlzRn5+fjcd19nZWc7OzvlWJwAAgD0U6jN2/5aSkqIjR46oXLly2W4PDw9XTEyMzbq1a9cqPDy8IMoDAACwq0Id7EaOHKkNGzYoLi5OmzZtUqdOneTo6Khu3bpJknr06KHRo0db2z///POKjo7WlClTdODAAUVFRWnHjh0aPHiwvQ4BAACgwBTqS7EnTpxQt27ddOHCBXl7e6tJkybasmWLvL29JUnx8fFycPi/bNqoUSMtXLhQY8aM0SuvvKLg4GCtWLFCNWvWtNchAAAAFBiLYRiGvYsobJKTk+Xp6amkpCR5eHjYuxyg4EV52rsCIItagRXsXQKQrT0999zV8fOSSwr1pVgAAADkHsEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkQ7AAAAEyCYAcAAGASBDsAAACTINgBAACYBMEOAADAJAh2AAAAJkGwAwAAMAmCHQAAgEkU6mA3adIkNWjQQO7u7vLx8VHHjh118ODBm/aZP3++LBaLzcvFxaWAKgYAALCfQh3sNmzYoEGDBmnLli1au3atrl+/rlatWuny5cs37efh4aHTp09bX8eOHSugigEAAOynmL0LuJno6Gib5fnz58vHx0c7d+7Uww8/nGM/i8UiPz+/u10eAABAoVKoz9j9W1JSkiSpdOnSN22XkpKiihUryt/fXx06dNDvv/9+0/apqalKTk62eQEAABQ1RSbYZWRkaNiwYWrcuLFq1qyZY7uqVatq7ty5+vrrr/XZZ58pIyNDjRo10okTJ3LsM2nSJHl6elpf/v7+d+MQAAAA7iqLYRiGvYvIjQEDBui7777TL7/8ovvvvz/X/a5fv67q1aurW7dumjhxYrZtUlNTlZqaal1OTk6Wv7+/kpKS5OHhcce1A0VOlKe9KwCyqBVYwd4lANna03PPXR0/OTlZnp6eucolhfoeu0yDBw/WqlWr9NNPP+Up1ElS8eLFVa9ePR0+fDjHNs7OznJ2dr7TMgEAAOyqUF+KNQxDgwcP1vLly/XDDz8oMDAwz2Okp6drz549Kleu3F2oEAAAoPAo1GfsBg0apIULF+rrr7+Wu7u7EhISJEmenp5ydXWVJPXo0UP33XefJk2aJEl67bXX9OCDD6py5cpKTEzU5MmTdezYMT377LN2Ow4AAICCUKiD3ezZsyVJzZo1s1k/b9489erVS5IUHx8vB4f/O/H4119/qV+/fkpISFCpUqUUGhqqTZs2KSQkpKDKBgAAsIsi8/BEQcrLTYqAKfHwBAohHp5AYVWYHp4o1PfYAQAAIPcIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEgQ7AAAAkyDYAQAAmATBDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEgQ7AAAAkyDYAQAAmATBDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEgQ7AAAAkyDYAQAAmATBDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOxQ5M2aNUsBAQFycXFRWFiYtm3bZu+SAACwC4IdirQlS5ZoxIgRGj9+vHbt2qU6deooMjJSZ8+etXdpAAAUOIIdirSpU6eqX79+6t27t0JCQjRnzhyVKFFCc+fOtXdpAAAUOIIdiqy0tDTt3LlTERER1nUODg6KiIjQ5s2b7VgZAAD2QbBDkXX+/Hmlp6fL19fXZr2vr68SEhLsVBUAAPZDsAMAADAJgh2KrLJly8rR0VFnzpyxWX/mzBn5+fnZqSoAAOyHYIciy8nJSaGhoYqJibGuy8jIUExMjMLDw+1YGQAA9lHM3gUAd2LEiBHq2bOn6tevr4YNG2r69Om6fPmyevfube/SAAAocEXijF1eJ6BdunSpqlWrJhcXF9WqVUurV68uoEpR0Lp27ap3331X48aNU926dRUbG6vo6OgsD1QAAHAvKPTBLq8T0G7atEndunVT3759tXv3bnXs2FEdO3bU3r17C7hyFJTBgwfr2LFjSk1N1datWxUWFmbvkgAAsAuLYRiGvYu4mbCwMDVo0EAzZ86U9M89VP7+/hoyZIhGjRqVpX3Xrl11+fJlrVq1yrruwQcfVN26dTVnzpxc7TM5OVmenp5KSkqSh4dH/hwIUJREedq7AiCLWoEV7F0CkK09Pffc1fHzkksK9T12mRPQjh492rruVhPQbt68WSNGjLBZFxkZqRUrVuS4n9TUVKWmplqXk5KSJP3zRgL3pNRC/e893KPSr6bbuwQgW3c7L2SOn5tzcYU62N1sAtoDBw5k2ychISHPE9ZOmjRJEyZMyLLe39//NqoGANwd++1dAJAtzwEFc5Xj0qVL8vS8+b4KdbArKKNHj7Y5y5eRkaGLFy+qTJkyslgsdqwMQFGWnJwsf39/HT9+nNs6ANw2wzB06dIllS9f/pZtC3Wwu50JaP38/PI8Ya2zs7OcnZ1t1nl5ed1e0QDwLx4eHgQ7AHfkVmfqMhXqp2JvZwLa8PBwm/aStHbtWiasBQAApleoz9hJt56AtkePHrrvvvs0adIkSdLzzz+vpk2basqUKWrXrp0WL16sHTt26MMPP7TnYQAAANx1hT7Yde3aVefOndO4ceOUkJCgunXr2kxAGx8fLweH/zvx2KhRIy1cuFBjxozRK6+8ouDgYK1YsUI1a9a01yEAuEc5Oztr/PjxWW71AIC7pdDPYwcAAIDcKdT32AEAACD3CHYAAAAmQbADAAAwCYIdABRSUVFRqlu3rr3LAFCEEOwA3FMSEhI0ZMgQBQUFydnZWf7+/mrfvn2W+S8Lg5EjR9rU1atXL3Xs2NF+BQEo9Ar9dCcAkF/i4uLUuHFjeXl5afLkyapVq5auX7+uNWvWaNCgQTn+BrW9uLm5yc3Nzd5lAChCOGMH4J4xcOBAWSwWbdu2TU888YSqVKmiGjVqaMSIEdqyZYukf+bG7NChg9zc3OTh4aEuXbrY/Exh5uXRuXPnqkKFCnJzc9PAgQOVnp6ud955R35+fvLx8dEbb7xhs2+LxaL//ve/evTRR1WiRAlVr15dmzdv1uHDh9WsWTOVLFlSjRo10pEjR7LsK/PPCxYs0Ndffy2LxSKLxaIff/xRaWlpGjx4sMqVKycXFxdVrFjROmE7gHsPwQ7APeHixYuKjo7WoEGDVLJkySzbvby8lJGRoQ4dOujixYvasGGD1q5dqz///FNdu3a1aXvkyBF99913io6O1qJFi/Txxx+rXbt2OnHihDZs2KC3335bY8aM0datW236TZw4UT169FBsbKyqVaump59+Wv3799fo0aO1Y8cOGYahwYMHZ1v/yJEj1aVLF7Vu3VqnT5/W6dOn1ahRI7333ntauXKlvvjiCx08eFCff/65AgIC8u19A1C0cCkWwD3h8OHDMgxD1apVy7FNTEyM9uzZo6NHj8rf31+S9Mknn6hGjRravn27GjRoIOmf36yeO3eu3N3dFRISoubNm+vgwYNavXq1HBwcVLVqVb399ttav369wsLCrOP37t1bXbp0kSS9/PLLCg8P19ixYxUZGSnpn59EzPy5xH9zc3OTq6urUlNT5efnZ10fHx+v4OBgNWnSRBaLRRUrVryzNwpAkcYZOwD3hNz8yM7+/fvl7+9vDXWSFBISIi8vL+3fv9+6LiAgQO7u7tZlX19fhYSE2Py8oa+vr86ePWszfu3atW22S1KtWrVs1l27dk3Jycm5Pq5evXopNjZWVatW1dChQ/X999/nui8A8yHYAbgnBAcHy2Kx5MsDEsWLF7dZtlgs2a7LyMjIsZ/FYslx3b/73cwDDzygo0ePauLEibp69aq6dOmizp0757o/AHMh2AG4J5QuXVqRkZGaNWuWLl++nGV7YmKiqlevruPHj+v48ePW9fv27VNiYqJCQkIKstxsOTk5KT09Pct6Dw8Pde3aVR999JGWLFmir776ShcvXrRDhQDsjWAH4J4xa9Yspaenq2HDhvrqq6906NAh7d+/X++9957Cw8MVERGhWrVqqXv37tq1a5e2bdumHj16qGnTpqpfv769y1dAQIB+++03HTx4UOfPn9f169c1depULVq0SAcOHNAff/yhpUuXys/PT15eXvYuF4AdEOwA3DOCgoK0a9cuNW/eXC+88IJq1qypli1bKiYmRrNnz5bFYtHXX3+tUqVK6eGHH1ZERISCgoK0ZMkSe5cuSerXr5+qVq2q+vXry9vbWxs3bpS7u7veeecd1a9fXw0aNFBcXJz1IQ4A9x6LkZs7igEAAFDo8U86AAAAkyDYAQAAmATBDgAAwCQIdgAAACZBsAMAADAJgh0AAIBJEOwAAABMgmAHAABgEgQ7AAAAkyDYAQAAmATBDgAAwCQIdgAAACbx/wBWNFePfjy3bAAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "helpers_summary = github_utils.summarize_user_metrics_for_repo(\n",
+ " combined,\n",
+ " repo=\"helpers\",\n",
+ ")\n",
+ "github_utils.plot_metrics_by_user(\n",
+ " helpers_summary,\n",
+ " repo=\"tutorials\",\n",
+ " metrics=['commits'],\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5b57c41c-163d-4aac-b55b-b223ae9de9a1",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## See stats of a user on multiple repos based on `commits`, `prs`, `additions` and `deletions`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "ce513fe8-1b34-4679-b3a9-fe00aa1b62a6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "krishna_summary = github_utils.summarize_repo_metrics_for_user(\n",
+ " combined,\n",
+ " user=\"tkpratardan\",\n",
+ ")\n",
+ "\n",
+ "# then plot PRs and commits across their repos\n",
+ "github_utils.plot_metrics_by_repo(\n",
+ " krishna_summary,\n",
+ " user=\"tkpratardan\",\n",
+ " metrics=['prs', 'commits','additions','deletions'],\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "0bfdaf57-a6f3-4620-bfd8-c539cb1f0ffc",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHWCAYAAAD6oMSKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAbuJJREFUeJzt3XlczdnjP/DXbbm3UreFVirJUhElWxhCI4kRYSxDyJ59N2MpZuRj3xkzlJlhjIxtsibbGBmJ7IylxGgxqBTt798fvr1/rlspSrlez8fjPqZ7znmf9zn31vWa93KuRBAEAURERET00VOr6AEQERERUdlgsCMiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLCjT15ISAgkEgni4uIqeigftcr+OiYlJaFnz56oWrUqJBIJVqxYUSHjGDRoEHR1dStk35VJXFwcJBIJQkJCKnooRCqFwY4+mIJ/+CUSCU6fPq1ULwgCLC0tIZFI0KVLl3fax7p16/gPBRVq4sSJOHz4MGbOnImff/4ZnTp1Krd9vXjxAgEBAThx4kS57aMsXb9+HQEBAZU2lBNRyTHY0QenpaWFbdu2KZWfPHkSDx8+hEwme+e+3yXYDRgwAC9fvoS1tfU775cq/+t47NgxdOvWDVOmTMFXX30FOzu7ctvXixcvEBgY+FEFu8DAQAY7IhXAYEcfXOfOnREaGorc3FyF8m3btsHFxQVmZmYfZBwZGRkAAHV1dWhpaUEikXyQ/aqaj+V1TE5OhoGBQZn1l5mZifz8/DLrrywVvCcV7cWLFxU9hApRWV7/wuTm5iI7O7uih0HliMGOPri+ffviyZMnCA8PF8uys7Oxc+dO9OvXr9Bt8vPzsWLFCtSvXx9aWlowNTXFiBEj8OzZM7FNzZo1ce3aNZw8eVI85evm5gbg/58GPnnyJEaPHg0TExPUqFFDoe7NoxUHDx5E27ZtoaenB7lcjqZNmxZ6pPFN//77L/z8/GBhYQGZTAYbGxuMGjVK4cP03r176NWrF4yMjKCjo4MWLVpg//79Cv2cOHECEokEO3bsQGBgIKpXrw49PT307NkTqampyMrKwoQJE2BiYgJdXV0MHjwYWVlZCn1IJBKMGTMGW7duRb169aClpQUXFxecOnVKod39+/cxevRo1KtXD9ra2qhatSp69eql9JqU9nU8f/48PDw8UK1aNWhra8PGxgZDhgxR6DMjIwOTJ0+GpaUlZDIZ6tWrhyVLlkAQhELnsmfPHjRo0AAymQz169fHoUOHin0/CsYlCALWrl0r/m68y3uxfft2zJo1C9WrV4eOjg7S0tKU9hcXFwdjY2MAQGBgoLi/gICAIscYExMDY2NjuLm5IT09HcCr3+cuXbrgyJEjcHJygpaWFhwcHLBr165C51fYe1KS9zUkJAS9evUCALRr104cb8HRxr1798LLy0v8fba1tcX8+fORl5enMA43Nzc0aNAA0dHRaNOmDXR0dPD1118DAFJSUjBo0CDo6+vDwMAAvr6+SElJUXodLl++jEGDBqFWrVrQ0tKCmZkZhgwZgidPnii0CwgIgEQiwZ07dzBo0CAYGBhAX18fgwcPLlGY/PPPP9GrVy9YWVlBJpPB0tISEydOxMuXL5Xa3rx5E71794axsTG0tbVRr149fPPNN0pjuX79Ovr16wdDQ0O0bt0awKsQNX/+fNja2kImk6FmzZr4+uuvlf5OS/J3sn37dri4uIifR46Ojli5cmWx8yy4jnHJkiVYsWKFOI7r16+Lc+vZsyeMjIygpaWFJk2aYN++fQp9FPx+nTp1CiNGjEDVqlUhl8sxcOBAhc/fAuvWrUP9+vUhk8lgYWEBf39/pff69u3b8PHxgZmZGbS0tFCjRg306dMHqampxc6HSkajogdAn56aNWvC1dUVv/76Kzw9PQG8ClGpqano06cPVq1apbTNiBEjEBISgsGDB2PcuHGIjY3FmjVrcPHiRfz111/Q1NTEihUrMHbsWOjq6oofvKampgr9jB49GsbGxpgzZ06x/1cdEhKCIUOGoH79+pg5cyYMDAxw8eJFHDp0qMjwCQCPHj1Cs2bNkJKSguHDh8POzg7//vsvdu7ciRcvXkAqlSIpKQktW7bEixcvMG7cOFStWhVbtmzBF198gZ07d6J79+4KfQYFBUFbWxszZszAnTt3sHr1amhqakJNTQ3Pnj1DQEAAzp49i5CQENjY2GDOnDkK2588eRK//fYbxo0bB5lMhnXr1qFTp044d+4cGjRoAACIiorCmTNn0KdPH9SoUQNxcXFYv3493NzccP36dejo6JT6dUxOTkbHjh1hbGyMGTNmwMDAAHFxcQrBRBAEfPHFFzh+/Dj8/Pzg5OSEw4cPY+rUqfj333+xfPlyhT5Pnz6NXbt2YfTo0dDT08OqVavg4+OD+Ph4VK1atdBxtGnTBj///DMGDBiAzz//HAMHDhTrSvtezJ8/H1KpFFOmTEFWVhakUqnS/oyNjbF+/XqMGjUK3bt3R48ePQAADRs2LHR8UVFR8PDwQJMmTbB3715oa2uLdbdv38aXX36JkSNHwtfXF8HBwejVqxcOHTqEzz//XKGfwt6Tkryvbdq0wbhx47Bq1Sp8/fXXsLe3BwDxvyEhIdDV1cWkSZOgq6uLY8eOYc6cOUhLS8PixYsVxvDkyRN4enqiT58++Oqrr2BqagpBENCtWzecPn0aI0eOhL29PXbv3g1fX1+l1yI8PBz37t3D4MGDYWZmhmvXrmHjxo24du0azp49q3Q0uHfv3rCxsUFQUBAuXLiAH3/8ESYmJvjf//5X6GtdIDQ0FC9evMCoUaNQtWpVnDt3DqtXr8bDhw8RGhoqtrt8+TI+++wzaGpqYvjw4ahZsybu3r2LP/74A999951Cn7169UKdOnWwYMEC8X9Khg4dii1btqBnz56YPHky/v77bwQFBeHGjRvYvXs3gJL9nYSHh6Nv377o0KGDOLcbN27gr7/+wvjx44udKwAEBwcjMzMTw4cPh0wmg5GREa5du4ZWrVqhevXqmDFjBqpUqYIdO3bA29sbv//+u9Lv/pgxY2BgYICAgADcunUL69evx/3798X/6QFehdzAwEC4u7tj1KhRYruoqCjxczo7OxseHh7IysrC2LFjYWZmhn///RdhYWFISUmBvr7+W+dDbyEQfSDBwcECACEqKkpYs2aNoKenJ7x48UIQBEHo1auX0K5dO0EQBMHa2lrw8vISt/vzzz8FAMLWrVsV+jt06JBSef369YW2bdsWue/WrVsLubm5hdbFxsYKgiAIKSkpgp6entC8eXPh5cuXCm3z8/OLnePAgQMFNTU1ISoqSqmuYNsJEyYIAIQ///xTrHv+/LlgY2Mj1KxZU8jLyxMEQRCOHz8uABAaNGggZGdni2379u0rSCQSwdPTU6F/V1dXwdraWqEMgABAOH/+vFh2//59QUtLS+jevbtYVvA+vC4yMlIAIPz0009iWWlex927d4vvd1H27NkjABC+/fZbhfKePXsKEolEuHPnjsJcpFKpQtmlS5cEAMLq1auL3Mfr2/v7+yuUlfa9qFWrVqGv1ZseP34sABDmzp2rVOfr6ytUqVJFEARBOH36tCCXywUvLy8hMzNToZ21tbUAQPj999/FstTUVMHc3FxwdnYWy4p7T0r6voaGhgoAhOPHjyu1L6yPESNGCDo6Ogpjbtu2rQBA2LBhg0Lbgvd40aJFYllubq7w2WefCQCE4ODgYvf166+/CgCEU6dOiWVz584VAAhDhgxRaNu9e3ehatWqSn2UZE5BQUGCRCIR7t+/L5a1adNG0NPTUygTBMXPgYKx9O3bV6FNTEyMAEAYOnSoQvmUKVMEAMKxY8cEQSjZ38n48eMFuVyu9P6+TWxsrABAkMvlQnJyskJdhw4dBEdHR4X3MD8/X2jZsqVQp04dsazg98vFxUXhc2jRokUCAGHv3r2CIAhCcnKyIJVKhY4dO4p/N4IgCGvWrBEACJs3bxYEQRAuXrwoABBCQ0NLNRcqOZ6KpQrRu3dvvHz5EmFhYXj+/DnCwsKKPBIWGhoKfX19fP755/jvv//Eh4uLC3R1dXH8+PES73fYsGFQV1cvtk14eDieP3+OGTNmQEtLS6GuuOvH8vPzsWfPHnTt2hVNmjRRqi/Y9sCBA2jWrJl4ugYAdHV1MXz4cMTFxYmnSQoMHDgQmpqa4vPmzZtDEASlUzXNmzfHgwcPlK5ddHV1hYuLi/jcysoK3bp1w+HDh8XTaa8fJcrJycGTJ09Qu3ZtGBgY4MKFC0pzKcnrWHA9W1hYGHJycgptc+DAAairq2PcuHEK5ZMnT4YgCDh48KBCubu7O2xtbcXnDRs2hFwux71794odS1FK+174+voqvFbv4/jx4/Dw8ECHDh2wa9euQm8asrCwUDhyUnAK7OLFi0hMTFRoW9h7Utr3tTCv9/H8+XP8999/+Oyzz/DixQvcvHlToa1MJsPgwYMVyg4cOAANDQ2MGjVKLFNXV8fYsWOL3VdmZib+++8/tGjRAgAKHe/IkSMVnn/22Wd48uRJoafIi9pPRkYG/vvvP7Rs2RKCIODixYsAgMePH+PUqVMYMmQIrKysFLYv7HPgzbEcOHAAADBp0iSF8smTJwOAeLq/JH8nBgYGyMjIULh8pTR8fHzEywMA4OnTpzh27Bh69+4tvqf//fcfnjx5Ag8PD9y+fRv//vuvQh/Dhw9X+BwaNWoUNDQ0xHkePXoU2dnZmDBhAtTU/n+0GDZsGORyuTjfgiNyhw8f/mSvwSxvDHZUIYyNjeHu7o5t27Zh165dyMvLQ8+ePQtte/v2baSmpsLExATGxsYKj/T0dCQnJ5d4vzY2Nm9tc/fuXQAQT1OW1OPHj5GWlvbW7e7fv4969eoplRec+rp//75C+Zv/qBR8MFpaWiqV5+fnK12nUqdOHaV91a1bFy9evMDjx48BAC9fvsScOXPE69yqVasGY2NjpKSkFHrdS0lex7Zt28LHxweBgYGoVq0aunXrhuDgYIXri+7fvw8LCwvo6ekpbFvS1wIADA0NC73WpyRK+16UZN4lkZmZCS8vLzg7O2PHjh2FntIFgNq1ayuFiLp16wKA0vWPhY2ttO9rYa5du4bu3btDX18fcrkcxsbG+OqrrwBAqY/q1asrzeX+/fswNzdXWruvsNf96dOnGD9+PExNTaGtrQ1jY2NxXoWN983fB0NDQwB46+9DfHw8Bg0aBCMjI+jq6sLY2Bht27ZV2E/B/yyU9HPgzdf//v37UFNTQ+3atRXKzczMYGBgIP5uleTvZPTo0ahbty48PT1Ro0YNDBky5K3XlhY3tjt37kAQBMyePVvpM3Xu3LkAoPS5+ubniK6uLszNzcXfw4L5vPm+SqVS1KpVS6y3sbHBpEmT8OOPP6JatWrw8PDA2rVreX1dGeI1dlRh+vXrh2HDhiExMRGenp5F3rGYn58PExMTbN26tdD61/9P9G3K6mjLh1TUkbGiyoU3bjooibFjxyI4OBgTJkyAq6sr9PX1IZFI0KdPn0Lv/CzJ6yiRSLBz506cPXsWf/zxBw4fPowhQ4Zg6dKlOHv27Dst0luWc34XZfX7I5PJ0LlzZ+zduxeHDh1653UbX1fY2Er7vr4pJSUFbdu2hVwux7x582BrawstLS1cuHAB06dPV+rjfV+f3r1748yZM5g6dSqcnJygq6uL/Px8dOrUqdDxvsvvQ15eHj7//HM8ffoU06dPh52dHapUqYJ///0XgwYNeuc7nYua+9vuEi/J34mJiQliYmJw+PBhHDx4EAcPHkRwcDAGDhyILVu2lHpsBXOcMmUKPDw8Ct3mzUBalpYuXYpBgwZh7969OHLkCMaNG4egoCCcPXtWvPGH3h2DHVWY7t27Y8SIETh79ix+++23ItvZ2tri6NGjaNWq1Vv/4SiLpTYKTvVdvXq1VB9uxsbGkMvluHr1arHtrK2tcevWLaXygtNaZb0O3O3bt5XK/vnnH+jo6IiheOfOnfD19cXSpUvFNpmZmYXeuVhaLVq0QIsWLfDdd99h27Zt6N+/P7Zv346hQ4fC2toaR48exfPnzxWO2pXXa/Gm8novSvKP+datW9GtWzf06tULBw8eFO/gfl3BkZXX+/vnn38AvLoJ6W1K+r4WNd4TJ07gyZMn2LVrF9q0aSOWx8bGvnXfBaytrREREYH09HSFMP/m6/7s2TNEREQgMDBQ4Qagwn5/38eVK1fwzz//YMuWLQo30rx5mrNWrVoA8Na/56JYW1sjPz8ft2/fFo8AA69u2ElJSVH63Sru7wR4deSra9eu6Nq1K/Lz8zF69Gh8//33mD17dqlDWMHcNDU14e7uXqJtbt++jXbt2onP09PTkZCQgM6dO4vzBV69rwX9A69WPIiNjVXaj6OjIxwdHTFr1iycOXMGrVq1woYNG/Dtt9+Wai6kjKdiqcLo6upi/fr1CAgIQNeuXYts17t3b+Tl5WH+/PlKdbm5uQr/SFWpUuW9w0jHjh2hp6eHoKAgZGZmKtQVdyRATU0N3t7e+OOPP3D+/Hml+oJtO3fujHPnziEyMlKsy8jIwMaNG1GzZk04ODi81/jfFBkZqXB90oMHD7B371507NhRPOKhrq6uNLfVq1crLWlRGs+ePVPq08nJCQDE00ydO3dGXl4e1qxZo9Bu+fLlkEgk4l3T5aW83ouCu4iL+12USqXYtWsXmjZtiq5du+LcuXNKbR49eiTePQkAaWlp+Omnn+Dk5FSi9R5L+r5WqVKl0PEW/H683kd2djbWrVv31n0X6Ny5M3Jzc7F+/XqxLC8vD6tXr37rvgCU+Ve/FbYfQRCUlg4xNjZGmzZtsHnzZsTHxyvUleQIcUHgeXP8y5YtAwB4eXkBKNnfyZvLvaipqYl3Wb+5dEpJmJiYwM3NDd9//z0SEhKU6gsu0Xjdxo0bFa4BXL9+PXJzc8W/UXd3d0ilUqxatUphPps2bUJqaqo437S0NKXrgB0dHaGmpvZOcyFlPGJHFaqwJQ/e1LZtW4wYMQJBQUGIiYlBx44doampidu3byM0NBQrV64Ur89zcXHB+vXr8e2336J27dowMTFB+/btSzUmuVyO5cuXY+jQoWjatKm4NtWlS5fw4sWLYk99LFiwAEeOHEHbtm0xfPhw2NvbIyEhAaGhoTh9+jQMDAwwY8YMcamXcePGwcjICFu2bEFsbCx+//13hQuPy0KDBg3g4eGhsNwJ8GqNtQJdunTBzz//DH19fTg4OCAyMhJHjx4tcgmRktiyZQvWrVuH7t27w9bWFs+fP8cPP/wAuVwu/qPXtWtXtGvXDt988w3i4uLQqFEjHDlyBHv37sWECRMUbpQoD+X1Xmhra8PBwQG//fYb6tatCyMjIzRo0EDpei1tbW2EhYWhffv28PT0xMmTJxXa1K1bF35+foiKioKpqSk2b96MpKQkBAcHl2gcJX1fnZycoK6ujv/9739ITU2FTCZD+/bt0bJlSxgaGsLX1xfjxo2DRCLBzz//XKpT3127dkWrVq0wY8YMxMXFiWvxvXlNlVwuR5s2bbBo0SLk5OSgevXqOHLkSKmODpaEnZ0dbG1tMWXKFPz777+Qy+X4/fffC70ub9WqVWjdujUaN26M4cOHw8bGBnFxcdi/fz9iYmKK3U+jRo3g6+uLjRs3iqe0z507hy1btsDb21s8+lWSv5OhQ4fi6dOnaN++PWrUqIH79+9j9erVcHJyUjgaWBpr165F69at4ejoiGHDhqFWrVpISkpCZGQkHj58iEuXLim0z87ORocOHdC7d2/cunUL69atQ+vWrfHFF18AeBWEZ86cicDAQHTq1AlffPGF2K5p06bidZnHjh3DmDFj0KtXL9StWxe5ubn4+eefoa6uDh8fn3eaC73hg96DS5+015c7Kc6by50U2Lhxo+Di4iJoa2sLenp6gqOjozBt2jTh0aNHYpvExETBy8tL0NPTEwCIS58Ut+83l+kosG/fPqFly5aCtra2IJfLhWbNmgm//vrrW+d5//59YeDAgYKxsbEgk8mEWrVqCf7+/kJWVpbY5u7du0LPnj0FAwMDQUtLS2jWrJkQFham0E/BEhtvLgtQ1FwKll14/PixWIb/W+Ljl19+EerUqSPIZDLB2dlZaVmLZ8+eCYMHDxaqVasm6OrqCh4eHsLNmzcFa2trwdfX9637Lux1vHDhgtC3b1/ByspKkMlkgomJidClSxeFpVcE4dXyIhMnThQsLCwETU1NoU6dOsLixYuVlpYpmMub3hxjUYra/n3ei+KcOXNGcHFxEaRSqcLSJ68vd1Lgv//+ExwcHAQzMzPh9u3b4ry8vLyEw4cPCw0bNhRkMplgZ2dX4t8HQSj5+yoIgvDDDz8ItWrVEtTV1RWWPvnrr7+EFi1aCNra2oKFhYUwbdo04fDhw0rLo7Rt21aoX79+oa/FkydPhAEDBghyuVzQ19cXBgwYIC578fpyJw8fPhS6d+8uGBgYCPr6+kKvXr2ER48eKS0dU9jv+uuvxZt/y2+6fv264O7uLujq6grVqlUThg0bJi6d8/p4BEEQrl69Ko5JS0tLqFevnjB79uy3jkUQBCEnJ0cIDAwUbGxsBE1NTcHS0lKYOXOmwhIjJfk72blzp9CxY0fBxMREkEqlgpWVlTBixAghISGh2HkWLHeyePHiQuvv3r0rDBw4UDAzMxM0NTWF6tWrC126dBF27twptil4TU+ePCkMHz5cMDQ0FHR1dYX+/fsLT548UepzzZo1gp2dnaCpqSmYmpoKo0aNEp49eybW37t3TxgyZIhga2sraGlpCUZGRkK7du2Eo0ePFjsXKjmJIHygq46J6IOTSCTw9/dXOtVJlV/NmjXRoEEDhIWFVfRQ6BNWsDB8VFRUocs4UeXDa+yIiIiIVASDHREREZGKYLAjIiIiUhG8xo6IiIhIRfCIHREREZGKYLAjIiIiUhFcoLiM5Ofn49GjR9DT0yuTr7UiIiIiAl5928nz589hYWHx1oXTGezKyKNHj2BpaVnRwyAiIiIV9eDBA9SoUaPYNgx2ZaTgC8wfPHgAuVxewaMhIiIiVZGWlgZLS0sxaxSHwa6MFJx+lcvlDHZERERU5kpyqRdvniAiIiJSEQx2RERERCqiQoNdUFAQmjZtCj09PZiYmMDb2xu3bt1SaJOZmQl/f39UrVoVurq68PHxQVJSkkKb+Ph4eHl5QUdHByYmJpg6dSpyc3MV2pw4cQKNGzeGTCZD7dq1ERISojSetWvXombNmtDS0kLz5s1x7ty5Mp8zERERUXmp0GvsTp48CX9/fzRt2hS5ubn4+uuv0bFjR1y/fh1VqlQBAEycOBH79+9HaGgo9PX1MWbMGPTo0QN//fUXACAvLw9eXl4wMzPDmTNnkJCQgIEDB0JTUxMLFiwAAMTGxsLLywsjR47E1q1bERERgaFDh8Lc3BweHh4AgN9++w2TJk3Chg0b0Lx5c6xYsQIeHh64desWTExMKuYFIiIiKgP5+fnIzs6u6GFQETQ1NaGurl4mfVWqrxR7/PgxTExMcPLkSbRp0wapqakwNjbGtm3b0LNnTwDAzZs3YW9vj8jISLRo0QIHDx5Ely5d8OjRI5iamgIANmzYgOnTp+Px48eQSqWYPn069u/fj6tXr4r76tOnD1JSUnDo0CEAQPPmzdG0aVOsWbMGwKs/AktLS4wdOxYzZsx469jT0tKgr6+P1NRU3jxBKuvUqVNYvHgxoqOjkZCQgN27d8Pb21usT0pKwvTp03HkyBGkpKSgTZs2WL16NerUqaPUlyAI6Ny5Mw4dOqTQT0hICAYPHlzo/pOSksT/0crKysK8efPwyy+/IDExEebm5pgzZw6GDBlS5vMm+phlZ2cjNjYW+fn5FT0UKoaBgQHMzMwKvUGiNBmjUt0Vm5qaCgAwMjICAERHRyMnJwfu7u5iGzs7O1hZWYnBLjIyEo6OjmKoAwAPDw+MGjUK165dg7OzMyIjIxX6KGgzYcIEAK9+6aOjozFz5kyxXk1NDe7u7oiMjCx0rFlZWcjKyhKfp6Wlvd/kiT4CGRkZaNSoEYYMGYIePXoo1AmCAG9vb2hqamLv3r2Qy+VYtmwZ3N3dFY7CF1ixYkWhH2BffvklOnXqpFA2aNAgZGZmKhw97927N5KSkrBp0ybUrl0bCQkJ/IeL6A2CICAhIQHq6uqwtLR86+K29OEJgoAXL14gOTkZAGBubv5e/VWaYJefn48JEyagVatWaNCgAQAgMTERUqkUBgYGCm1NTU2RmJgotnk91BXUF9QV1yYtLQ0vX77Es2fPkJeXV2ibmzdvFjreoKAgBAYGvttkiT5Snp6e8PT0LLTu9u3bOHv2LK5evYr69esDANavXw8zMzP8+uuvGDp0qNg2JiYGS5cuxfnz55U+xLS1taGtrS0+f/z4MY4dO4ZNmzaJZYcOHcLJkydx79498X8Ea9asWVbTJFIZubm5ePHiBSwsLKCjo1PRw6EiFHzmJScnw8TE5L1Oy1aa6O7v74+rV69i+/btFT2UEpk5cyZSU1PFx4MHDyp6SEQVquAItpaWllimpqYGmUyG06dPi2UvXrxAv379sHbtWpiZmb21359++gk6Ojri5RgAsG/fPjRp0gSLFi1C9erVUbduXUyZMgUvX74swxkRffzy8vIAAFKptIJHQm9TELxzcnLeq59KccRuzJgxCAsLw6lTpxS+KsPMzAzZ2dlISUlROGqXlJQk/oNgZmamdPdqwV2zr7d5807apKQkyOVyaGtrQ11dHerq6oW2KeofHplMBplM9m4TJlJBBZdJzJw5E99//z2qVKmC5cuX4+HDh0hISBDbTZw4ES1btkS3bt1K1O+mTZvQr18/haN49+7dw+nTp6GlpYXdu3fjv//+w+jRo/HkyRMEBweX+dyIPnb8DvPKr6zeowo9YicIAsaMGYPdu3fj2LFjsLGxUah3cXGBpqYmIiIixLJbt24hPj4erq6uAABXV1dcuXJFPDcNAOHh4ZDL5XBwcBDbvN5HQZuCPqRSKVxcXBTa5OfnIyIiQmxDRMXT1NTErl278M8//8DIyAg6Ojo4fvw4PD09xet69u3bh2PHjmHFihUl6jMyMhI3btyAn5+fQnl+fj4kEgm2bt2KZs2aoXPnzli2bBm2bNnCo3ZE9Emr0GDn7++PX375Bdu2bYOenh4SExORmJgofjDr6+vDz88PkyZNwvHjxxEdHY3BgwfD1dUVLVq0AAB07NgRDg4OGDBgAC5duoTDhw9j1qxZ8Pf3F4+ojRw5Evfu3cO0adNw8+ZNrFu3Djt27MDEiRPFsUyaNAk//PADtmzZghs3bmDUqFHIyMgo8u48IlLm4uKCmJgYpKSkICEhAYcOHcKTJ09Qq1YtAMCxY8dw9+5dGBgYQENDAxoar04a+Pj4wM3NTam/H3/8EU5OTnBxcVEoNzc3R/Xq1aGvry+W2dvbQxAEPHz4sPwmSERUyVXoqdj169cDgNIHenBwMAYNGgQAWL58OdTU1ODj44OsrCx4eHhg3bp1Ylt1dXWEhYVh1KhRcHV1RZUqVeDr64t58+aJbWxsbLB//35MnDgRK1euRI0aNfDjjz+Ka9gBr+7Ee/z4MebMmYPExEQ4OTnh0KFDSjdUENHbFQSu27dv4/z585g/fz4AYMaMGQo3UQCAo6Mjli9fjq5duyqUp6enY8eOHQgKClLqv1WrVggNDUV6ejp0dXUBAP/88w/U1NQULucgosLVnLH/g+4vbqHXB93fp6xSrWP3MeM6dvQpSE9Px507dwAAzs7OWLZsGdq1awcjIyNYWVkhNDQUxsbGsLKywpUrVzB+/Hi4uLjg999/L7JPiUSitB4e8OraujFjxiAhIUHpzvj09HTY29ujRYsWCAwMxH///YehQ4eibdu2+OGHH8p62kQfrczMTMTGxsLGxkbhxiYGu8qnqPcKKF3GqDR3xRJR5Xf+/Hk4OzvD2dkZwKtLGJydnTFnzhwAQEJCAgYMGAA7OzuMGzcOAwYMwK+//vpO+9q0aRN69OihFOoAQFdXF+Hh4UhJSUGTJk3Qv39/dO3aFatWrXrnuRFR5ZKfn49Fixahdu3akMlksLKywnfffYe4uDhIJBLs2LEDn332GbS1tdG0aVP8888/iIqKQpMmTaCrqwtPT088fvxY7C8qKgqff/45qlWrBn19fbRt2xYXLlxQ2KdEIsH333+PLl26QEdHR/xChDt37sDNzQ1VqlRBy5YtcffuXXGbgIAAODk54fvvv4elpSV0dHTQu3dvcW3eD41H7MoIj9gREVFl8zEfsZs+fTp++OEHLF++HK1bt0ZCQgJu3rwJd3d32NjYwM7ODitWrICVlRWGDBmCnJwc6Onp4dtvvxXDlbu7u3jZ17Fjx/Do0SM0adIEgiBg6dKlCAsLw+3bt6GnpwfgVbCrXr06li1bBicnJ0yfPh0xMTGoVasWpk2bJu7LwMAABw8eBPAq2C1ZsgTNmzfH0qVLkZaWBj8/PzRr1gxbt24t8XzL6ohdpVjuhIiIiKjA8+fPsXLlSqxZswa+vr4AAFtbW7Ru3RpxcXEAgClTpojXyo8fPx59+/ZFREQEWrVqBQDw8/NDSEiI2Gf79u0V9rFx40YYGBjg5MmT6NKli1g+ePBg9O7dG8CrcOnq6orZs2cr7OvNGyszMzPx008/oXr16gCA1atXw8vLC0uXLi3Rep1liadiiYiIqFK5ceMGsrKy0KFDhyLbNGzYUPy54EZHR0dHhbLXl0JLSkrCsGHDUKdOHejr60MulyM9PR3x8fGl7jczM1Phq0StrKzEUAe8WmYtPz8ft27dKvGcywqP2BF9Qhy3OL690Sfsiu+Vih4CEQEKC5IXRVNTU/y5YHHfN8te//5oX19fPHnyBCtXroS1tTVkMhlcXV2RnZ1d6n4BVNrvpuYROyIiIqpU6tSpA21tbaUvF3gff/31F8aNG4fOnTujfv36kMlk+O+//8qk7/j4eDx69Eh8fvbsWaipqaFevXpl0n9p8IgdERERVSpaWlqYPn06pk2bBqlUilatWuHx48e4du1asadni1OnTh38/PPPaNKkCdLS0jB16tQSHRks6Xh9fX2xZMkSpKWlYdy4cejdu/cHv74OYLAjIiKiSmj27NnQ0NDAnDlz8OjRI5ibm2PkyJHv3N+mTZswfPhwNG7cGJaWlliwYAGmTJlSJmOtXbs2evTogc6dO+Pp06fo0qWLwpcpfEhc7qSMcLkT+hjwGrvi8Ro7UjXFLaFBZSMgIAB79uxBTEzMe/XDBYqJiIiISAGDHREREZGKYLAjIiIiekcBAQHvfRq2LDHYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkRERFSpuLm5YcKECe+8fUBAAJycnMpsPB8TflcsERHRpyZA/wPvL/XD7u8TxiN2RERERKUkCAJyc3MrehhKGOyIiIio0snPz8e0adNgZGQEMzMzBAQEiHUpKSkYOnQojI2NIZfL0b59e1y6dKnIvgYNGgRvb28EBgaK24wcORLZ2dkK+wsKCoKNjQ20tbXRqFEj7Ny5U6w/ceIEJBIJDh48CBcXF8hkMpw+fRqXLl1Cu3btoKenB7lcDhcXF5w/f75cXpOS4KlYIiIiqnS2bNmCSZMm4e+//0ZkZCQGDRqEVq1a4fPPP0evXr2gra2NgwcPQl9fH99//z06dOiAf/75B0ZGRoX2FxERAS0tLZw4cQJxcXEYPHgwqlatiu+++w4AEBQUhF9++QUbNmxAnTp1cOrUKXz11VcwNjZG27ZtxX5mzJiBJUuWoFatWjA0NESbNm3g7OyM9evXQ11dHTExMdDU1Pwgr1FhGOyIiIio0mnYsCHmzp0LAKhTpw7WrFmDiIgIaGtr49y5c0hOToZMJgMALFmyBHv27MHOnTsxfPjwQvuTSqXYvHkzdHR0UL9+fcybNw9Tp07F/PnzkZOTgwULFuDo0aNwdXUFANSqVQunT5/G999/rxDs5s2bh88//1x8Hh8fj6lTp8LOzk4ca0VisCMiIqJKp2HDhgrPzc3NkZycjEuXLiE9PR1Vq1ZVqH/58iXu3r1bZH+NGjWCjo6O+NzV1RXp6el48OAB0tPT8eLFC4XABgDZ2dlwdnZWKGvSpInC80mTJmHo0KH4+eef4e7ujl69esHW1rZUcy1LDHZERERU6bx5OlMikSA/Px/p6ekwNzfHiRMnlLYxMDB4p32lp6cDAPbv34/q1asr1BUcFSxQpUoVhecBAQHo168f9u/fj4MHD2Lu3LnYvn07unfv/k5jeV8MdkRERPTRaNy4MRITE6GhoYGaNWuWeLtLly7h5cuX0NbWBgCcPXsWurq6sLS0hJGREWQyGeLj4xVOu5ZU3bp1UbduXUycOBF9+/ZFcHAwgx0RERHR27i7u8PV1RXe3t5YtGgR6tati0ePHmH//v3o3r270qnSAtnZ2fDz88OsWbMQFxeHuXPnYsyYMVBTU4Oenh6mTJmCiRMnIj8/H61bt0Zqair++usvyOVy+Pr6Ftrny5cvMXXqVPTs2RM2NjZ4+PAhoqKi4OPjU54vQbEY7IiIiOijIZFIcODAAXzzzTcYPHgwHj9+DDMzM7Rp0wampqZFbtehQwfUqVMHbdq0QVZWFvr27auwhMr8+fNhbGyMoKAg3Lt3DwYGBmjcuDG+/vrrIvtUV1fHkydPMHDgQCQlJaFatWro0aMHAgMDy3LKpSIRBEGosL2rkLS0NOjr6yM1NRVyubyih0NUKMctjhU9hErtiu+Vih4CUZnKzMxEbGwsbGxsoKWlVdHDqTCDBg1CSkoK9uzZU9FDKVJx71VpMgYXKCYiIiJSEQx2RERERCqC19gRERGRSgsJCanoIXwwPGJHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqiQoPdqVOn0LVrV1hYWEAikSgtHCiRSAp9LF68WGxTs2ZNpfqFCxcq9HP58mV89tln0NLSgqWlJRYtWqQ0ltDQUNjZ2UFLSwuOjo44cOBAucyZiIiIqLxUaLDLyMhAo0aNsHbt2kLrExISFB6bN2+GRCJR+g62efPmKbQbO3asWJeWloaOHTvC2toa0dHRWLx4MQICArBx40axzZkzZ9C3b1/4+fnh4sWL8Pb2hre3N65evVo+EyciIqJKzc3NDRMmTChx+xMnTkAikSAlJaXcxlQSFbqOnaenJzw9PYusNzMzU3i+d+9etGvXDrVq1VIo19PTU2pbYOvWrcjOzsbmzZshlUpRv359xMTEYNmyZRg+fDgAYOXKlejUqROmTp0K4NX3xYWHh2PNmjXYsGHD+0yRiIio0vnQXy9Y2q/rc3Nzg5OTE1asWFHibQICArBnzx7ExMSUbnBF2LVrFzQ1Ncukrw/po7nGLikpCfv374efn59S3cKFC1G1alU4Oztj8eLFyM3NFesiIyPRpk0bSKVSsczDwwO3bt3Cs2fPxDbu7u4KfXp4eCAyMrKcZkNERESVUXZ2NgDAyMgIenp6FTya0vtogt2WLVugp6eHHj16KJSPGzcO27dvx/HjxzFixAgsWLAA06ZNE+sTExNhamqqsE3B88TExGLbFNQXJisrC2lpaQoPIiIiej+DBg3CyZMnsXLlSvHa+ZCQEBgYGCi027NnDyQSCYBX3ywRGBiIS5cuKWwDAPHx8ejWrRt0dXUhl8vRu3dvJCUlif0EBATAyckJP/74I2xsbKClpQVA+VTszz//jCZNmohnCfv164fk5OQi53H//n107doVhoaGqFKlCurXr/9Brt//aL5SbPPmzejfv7/4gheYNGmS+HPDhg0hlUoxYsQIBAUFQSaTldt4goKCEBgYWG79ExERfYpWrlyJf/75Bw0aNMC8efMAAPv37y92my+//BJXr17FoUOHcPToUQCAvr4+8vPzxVB38uRJ5Obmwt/fH19++SVOnDghbn/nzh38/vvv2LVrF9TV1QvdR05ODubPn4969eohOTkZkyZNwqBBg4oMa/7+/sjOzsapU6dQpUoVXL9+Hbq6uu/wipTORxHs/vzzT9y6dQu//fbbW9s2b94cubm5iIuLQ7169WBmZqaQzAGIzwuuyyuqTVHX7QHAzJkzFUJlWloaLC0tSzwnIiIiUqavrw+pVAodHR3x3+GiwlYBbW1t6OrqQkNDQ+Hf7vDwcFy5cgWxsbHiv9E//fQT6tevj6ioKDRt2hTAq9OvP/30E4yNjYvcx5AhQ8Sfa9WqhVWrVqFp06ZIT08vNLDFx8fDx8cHjo6O4jYfwkdxKnbTpk1wcXFBo0aN3to2JiYGampqMDExAQC4urri1KlTyMnJEduEh4ejXr16MDQ0FNtEREQo9BMeHg5XV9ci9yOTySCXyxUeREREVHncuHEDlpaWCgdeHBwcYGBggBs3bohl1tbWxYY6AIiOjkbXrl1hZWUFPT09tG3bFsCrAFeYcePG4dtvv0WrVq0wd+5cXL58uQxm9HYVGuzS09MRExMj3sESGxuLmJgYhRcpLS0NoaGhGDp0qNL2kZGRWLFiBS5duoR79+5h69atmDhxIr766isxtPXr1w9SqRR+fn64du0afvvtN6xcuVLhaNv48eNx6NAhLF26FDdv3kRAQADOnz+PMWPGlO8LQERERG+lpqYGQRAUyl4/YPO+qlSpUmx9RkYGPDw8IJfLsXXrVkRFRWH37t0A/v/NFm8aOnQo7t27hwEDBuDKlSto0qQJVq9eXWZjLkqFBrvz58/D2dkZzs7OAF5dL+fs7Iw5c+aIbbZv3w5BENC3b1+l7WUyGbZv3462bduifv36+O677zBx4kSFNer09fVx5MgRxMbGwsXFBZMnT8acOXPEpU4AoGXLlti2bRs2btyIRo0aYefOndizZw8aNGhQjrMnIiKiwkilUuTl5YnPjY2N8fz5c2RkZIhlby5r8uY2AGBvb48HDx7gwYMHYtn169eRkpICBweHEo/n5s2bePLkCRYuXIjPPvsMdnZ2xd44UcDS0hIjR47Erl27MHnyZPzwww8l3ue7qtBr7Nzc3JQS+JuGDx+uEMJe17hxY5w9e/at+2nYsCH+/PPPYtv06tULvXr1emtfREREVL5q1qyJv//+G3FxcdDV1UXz5s2ho6ODr7/+GuPGjcPff/8t3vX6+jYFZ/5q1KgBPT09uLu7w9HREf3798eKFSuQm5uL0aNHo23btmjSpEmJx2NlZQWpVIrVq1dj5MiRuHr1KubPn1/sNhMmTICnpyfq1q2LZ8+e4fjx47C3t3+Xl6NUPopr7IiIiOjTMWXKFKirq8PBwQHGxsZIS0vDL7/8ggMHDsDR0RG//vorAgICFLbx8fFBp06d0K5dOxgbG+PXX3+FRCLB3r17YWhoiDZt2sDd3R21atUq0c2YrzM2NkZISAhCQ0Ph4OCAhQsXYsmSJcVuk5eXB39/f9jb26NTp06oW7cu1q1bV9qXotQkwtsOmVGJpKWlQV9fH6mpqbyRgiqtD73a/MemtKvjE1V2mZmZiI2NVVifjSqn4t6r0mQMHrEjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERKTiuABG5Zefn18m/VToAsVERERUfjQ1NSGRSPD48WMYGxtDIpFU9JDoDYIgIDs7G48fP4aamhqkUul79cdgR0REpKLU1dVRo0YNPHz4EHFxcRU9HCqGjo4OrKysoKb2fidTGeyIiIhUmK6uLurUqYOcnJyKHgoVQV1dHRoaGmVyRJXBjoiISMWpq6tDXV29oodBHwBvniAiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqiQoPdqVOn0LVrV1hYWEAikWDPnj0K9YMGDYJEIlF4dOrUSaHN06dP0b9/f8jlchgYGMDPzw/p6ekKbS5fvozPPvsMWlpasLS0xKJFi5TGEhoaCjs7O2hpacHR0REHDhwo8/kSERERlacKDXYZGRlo1KgR1q5dW2SbTp06ISEhQXz8+uuvCvX9+/fHtWvXEB4ejrCwMJw6dQrDhw8X69PS0tCxY0dYW1sjOjoaixcvRkBAADZu3Ci2OXPmDPr27Qs/Pz9cvHgR3t7e8Pb2xtWrV8t+0kRERETlRCIIglDRgwAAiUSC3bt3w9vbWywbNGgQUlJSlI7kFbhx4wYcHBwQFRWFJk2aAAAOHTqEzp074+HDh7CwsMD69evxzTffIDExEVKpFAAwY8YM7NmzBzdv3gQAfPnll8jIyEBYWJjYd4sWLeDk5IQNGzaUaPxpaWnQ19dHamoq5HL5O7wCROXPcYtjRQ+hUrvie6Wih0BEpKQ0GaPSX2N34sQJmJiYoF69ehg1ahSePHki1kVGRsLAwEAMdQDg7u4ONTU1/P3332KbNm3aiKEOADw8PHDr1i08e/ZMbOPu7q6wXw8PD0RGRpbn1IiIiIjKlEZFD6A4nTp1Qo8ePWBjY4O7d+/i66+/hqenJyIjI6Guro7ExESYmJgobKOhoQEjIyMkJiYCABITE2FjY6PQxtTUVKwzNDREYmKiWPZ6m4I+CpOVlYWsrCzxeVpa2nvNlYiIiOh9Vepg16dPH/FnR0dHNGzYELa2tjhx4gQ6dOhQgSMDgoKCEBgYWKFjICIiInpdpT8V+7patWqhWrVquHPnDgDAzMwMycnJCm1yc3Px9OlTmJmZiW2SkpIU2hQ8f1ubgvrCzJw5E6mpqeLjwYMH7zc5IiIiovf0UQW7hw8f4smTJzA3NwcAuLq6IiUlBdHR0WKbY8eOIT8/H82bNxfbnDp1Cjk5OWKb8PBw1KtXD4aGhmKbiIgIhX2Fh4fD1dW1yLHIZDLI5XKFBxEREVFFqtBgl56ejpiYGMTExAAAYmNjERMTg/j4eKSnp2Pq1Kk4e/Ys4uLiEBERgW7duqF27drw8PAAANjb26NTp04YNmwYzp07h7/++gtjxoxBnz59YGFhAQDo168fpFIp/Pz8cO3aNfz2229YuXIlJk2aJI5j/PjxOHToEJYuXYqbN28iICAA58+fx5gxYz74a0JERET0rio02J0/fx7Ozs5wdnYGAEyaNAnOzs6YM2cO1NXVcfnyZXzxxReoW7cu/Pz84OLigj///BMymUzsY+vWrbCzs0OHDh3QuXNntG7dWmGNOn19fRw5cgSxsbFwcXHB5MmTMWfOHIW17lq2bIlt27Zh48aNaNSoEXbu3Ik9e/agQYMGH+7FICIiInpPlWYdu48d17GjjwHXsSse17EjospIpdaxIyIiIqKSYbAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIqNNidOnUKXbt2hYWFBSQSCfbs2SPW5eTkYPr06XB0dESVKlVgYWGBgQMH4tGjRwp91KxZExKJROGxcOFChTaXL1/GZ599Bi0tLVhaWmLRokVKYwkNDYWdnR20tLTg6OiIAwcOlMuciYiIiMpLhQa7jIwMNGrUCGvXrlWqe/HiBS5cuIDZs2fjwoUL2LVrF27duoUvvvhCqe28efOQkJAgPsaOHSvWpaWloWPHjrC2tkZ0dDQWL16MgIAAbNy4UWxz5swZ9O3bF35+frh48SK8vb3h7e2Nq1evls/EiYiIiMqBRkXu3NPTE56enoXW6evrIzw8XKFszZo1aNasGeLj42FlZSWW6+npwczMrNB+tm7diuzsbGzevBlSqRT169dHTEwMli1bhuHDhwMAVq5ciU6dOmHq1KkAgPnz5yM8PBxr1qzBhg0bymKqREREROXuo7rGLjU1FRKJBAYGBgrlCxcuRNWqVeHs7IzFixcjNzdXrIuMjESbNm0glUrFMg8PD9y6dQvPnj0T27i7uyv06eHhgcjIyCLHkpWVhbS0NIUHERERUUWq0CN2pZGZmYnp06ejb9++kMvlYvm4cePQuHFjGBkZ4cyZM5g5cyYSEhKwbNkyAEBiYiJsbGwU+jI1NRXrDA0NkZiYKJa93iYxMbHI8QQFBSEwMLCspkdERET03j6KYJeTk4PevXtDEASsX79eoW7SpEnizw0bNoRUKsWIESMQFBQEmUxWbmOaOXOmwr7T0tJgaWlZbvsjIiIieptKH+wKQt39+/dx7NgxhaN1hWnevDlyc3MRFxeHevXqwczMDElJSQptCp4XXJdXVJuirtsDAJlMVq7BkYiIiKi0KvU1dgWh7vbt2zh69CiqVq361m1iYmKgpqYGExMTAICrqytOnTqFnJwcsU14eDjq1asHQ0NDsU1ERIRCP+Hh4XB1dS3D2RARERGVrwo9Ypeeno47d+6Iz2NjYxETEwMjIyOYm5ujZ8+euHDhAsLCwpCXlyde82ZkZASpVIrIyEj8/fffaNeuHfT09BAZGYmJEyfiq6++EkNbv379EBgYCD8/P0yfPh1Xr17FypUrsXz5cnG/48ePR9u2bbF06VJ4eXlh+/btOH/+vMKSKERERESVnUQQBKGidn7ixAm0a9dOqdzX1xcBAQFKNz0UOH78ONzc3HDhwgWMHj0aN2/eRFZWFmxsbDBgwABMmjRJ4TTp5cuX4e/vj6ioKFSrVg1jx47F9OnTFfoMDQ3FrFmzEBcXhzp16mDRokXo3LlzieeSlpYGfX19pKamvvV0MVFFcdziWNFDqNSu+F6p6CEQESkpTcao0GCnShjs6GPAYFc8BjsiqoxKkzEq9TV2RERERFRyDHZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpiHcKdrVq1cKTJ0+UylNSUlCrVq33HhQRERERld47Bbu4uDjk5eUplWdlZeHff/9970ERERERUelplKbxvn37xJ8PHz4MfX198XleXh4iIiJQs2bNMhscEREREZVcqYKdt7c3AEAikcDX11ehTlNTEzVr1sTSpUvLbHBEREREVHKlCnb5+fkAABsbG0RFRaFatWrlMigiIiIiKr1SBbsCsbGxZT0OIiIiInpP7xTsACAiIgIRERFITk4Wj+QV2Lx583sPjIiIiIhK552CXWBgIObNm4cmTZrA3NwcEomkrMdFRERERKX0TsFuw4YNCAkJwYABA8p6PERERET0jt5pHbvs7Gy0bNmyrMdCRERERO/hnYLd0KFDsW3btrIeCxERERG9h3c6FZuZmYmNGzfi6NGjaNiwITQ1NRXqly1bViaDIyIiIqKSe6dgd/nyZTg5OQEArl69qlDHGymIiIiIKsY7Bbvjx4+X9TiIiIiI6D290zV2RERERFT5vNMRu3bt2hV7yvXYsWPvPCAiIiIiejfvFOwKrq8rkJOTg5iYGFy9ehW+vr5lMS4iIiIiKqV3CnbLly8vtDwgIADp6envNSAiIiIiejdleo3dV199VarviT116hS6du0KCwsLSCQS7NmzR6FeEATMmTMH5ubm0NbWhru7O27fvq3Q5unTp+jfvz/kcjkMDAzg5+enFC4vX76Mzz77DFpaWrC0tMSiRYuUxhIaGgo7OztoaWnB0dERBw4cKPnEiYiIiCqBMg12kZGR0NLSKnH7jIwMNGrUCGvXri20ftGiRVi1ahU2bNiAv//+G1WqVIGHhwcyMzPFNv3798e1a9cQHh6OsLAwnDp1CsOHDxfr09LS0LFjR1hbWyM6OhqLFy9GQEAANm7cKLY5c+YM+vbtCz8/P1y8eBHe3t7w9vZWWsqFiIiIqDKTCIIglHajHj16KDwXBAEJCQk4f/48Zs+ejblz55Z+IBIJdu/eDW9vb7FPCwsLTJ48GVOmTAEApKamwtTUFCEhIejTpw9u3LgBBwcHREVFoUmTJgCAQ4cOoXPnznj48CEsLCywfv16fPPNN0hMTIRUKgUAzJgxA3v27MHNmzcBAF9++SUyMjIQFhYmjqdFixZwcnLChg0bSjT+tLQ06OvrIzU1FXK5vNTzJ/oQHLc4VvQQKrUrvlcqeghEREpKkzHe6Yidvr6+wsPIyAhubm44cODAO4W6wsTGxiIxMRHu7u4K+23evDkiIyMBvDpCaGBgIIY6AHB3d4eamhr+/vtvsU2bNm3EUAcAHh4euHXrFp49eya2eX0/BW0K9kNERET0MXinmyeCg4PLehxKEhMTAQCmpqYK5aampmJdYmIiTExMFOo1NDRgZGSk0MbGxkapj4I6Q0NDJCYmFrufwmRlZSErK0t8npaWVprpEREREZW5dwp2BaKjo3Hjxg0AQP369eHs7Fwmg/oYBAUFITAwsKKHQURERCR6p1OxycnJaN++PZo2bYpx48Zh3LhxcHFxQYcOHfD48eMyGZiZmRkAICkpSaE8KSlJrDMzM0NycrJCfW5uLp4+farQprA+Xt9HUW0K6gszc+ZMpKamio8HDx6UdopEREREZeqdgt3YsWPx/PlzXLt2DU+fPsXTp09x9epVpKWlYdy4cWUyMBsbG5iZmSEiIkIsS0tLw99//w1XV1cAgKurK1JSUhAdHS22OXbsGPLz89G8eXOxzalTp5CTkyO2CQ8PR7169WBoaCi2eX0/BW0K9lMYmUwGuVyu8CAiIiKqSO8U7A4dOoR169bB3t5eLHNwcMDatWtx8ODBEveTnp6OmJgYxMTEAHh1w0RMTAzi4+MhkUgwYcIEfPvtt9i3bx+uXLmCgQMHwsLCQrxz1t7eHp06dcKwYcNw7tw5/PXXXxgzZgz69OkDCwsLAEC/fv0glUrh5+eHa9eu4bfffsPKlSsxadIkcRzjx4/HoUOHsHTpUty8eRMBAQE4f/48xowZ8y4vDxEREVGFeKdr7PLz86GpqalUrqmpifz8/BL3c/78ebRr1058XhC2fH19ERISgmnTpiEjIwPDhw9HSkoKWrdujUOHDimslbd161aMGTMGHTp0gJqaGnx8fLBq1SqxXl9fH0eOHIG/vz9cXFxQrVo1zJkzR2Gtu5YtW2Lbtm2YNWsWvv76a9SpUwd79uxBgwYNSvW6EBEREVWkd1rHrlu3bkhJScGvv/4qHhn7999/0b9/fxgaGmL37t1lPtDKjuvY0ceA69gVj+vYEVFlVO7r2K1ZswZpaWmoWbMmbG1tYWtrCxsbG6SlpWH16tXvNGgiIiIiej/vdCrW0tISFy5cwNGjR8Vvb7C3t1da5JeIiIiIPpxSHbE7duwYHBwckJaWBolEgs8//xxjx47F2LFj0bRpU9SvXx9//vlneY2ViIiIiIpRqmC3YsUKDBs2rNDzu/r6+hgxYgSWLVtWZoMjIiIiopIrVbC7dOkSOnXqVGR9x44dFdaUIyIiIqIPp1TBLikpqdBlTgpoaGiU2TdPEBEREVHplCrYVa9eHVevXi2y/vLlyzA3N3/vQRERERFR6ZUq2HXu3BmzZ89GZmamUt3Lly8xd+5cdOnSpcwGR0REREQlV6rlTmbNmoVdu3ahbt26GDNmDOrVqwcAuHnzJtauXYu8vDx888035TJQIiIiIipeqYKdqakpzpw5g1GjRmHmzJko+NIKiUQCDw8PrF27FqampuUyUCIiIiIqXqkXKLa2tsaBAwfw7Nkz3LlzB4IgoE6dOjA0NCyP8RERERFRCb3TN08AgKGhIZo2bVqWYyEiIiKi9/BO3xVLRERERJUPgx0RERGRimCwIyIiIlIRDHZEREREKoLB7hOWl5eH2bNnw8bGBtra2rC1tcX8+fPFZWxycnIwffp0ODo6okqVKrCwsMDAgQPx6NEjhX6++OILWFlZQUtLC+bm5hgwYIBSmx07dsDJyQk6OjqwtrbG4sWLP9g8iYiIPhUMdp+w//3vf1i/fj3WrFmDGzdu4H//+x8WLVqE1atXAwBevHiBCxcuYPbs2bhw4QJ27dqFW7du4YsvvlDop127dtixYwdu3bqF33//HXfv3kXPnj3F+oMHD6J///4YOXIkrl69inXr1mH58uVYs2bNB50vERGRqpMIBYdn6L2kpaVBX18fqampkMvlFT2cEunSpQtMTU2xadMmsczHxwfa2tr45ZdfCt0mKioKzZo1w/3792FlZVVom3379sHb2xtZWVnQ1NREv379kJOTg9DQULHN6tWrsWjRIsTHx0MikZTtxKhIjlscK3oIldoV3ysVPQQiIiWlyRg8YvcJa9myJSIiIvDPP/8AAC5duoTTp0/D09OzyG1SU1MhkUhgYGBQaP3Tp0+xdetWtGzZEpqamgCArKwsaGlpKbTT1tbGw4cPcf/+/bKZDBERETHYfcpmzJiBPn36wM7ODpqamnB2dsaECRPQv3//QttnZmZi+vTp6Nu3r9L/MUyfPh1VqlRB1apVER8fj71794p1Hh4e2LVrFyIiIpCfn49//vkHS5cuBQAkJCSU3wSJiIg+MQx2n7AdO3Zg69at2LZtGy5cuIAtW7ZgyZIl2LJli1LbnJwc9O7dG4IgYP369Ur1U6dOxcWLF3HkyBGoq6tj4MCB4k0Yw4YNw5gxY9ClSxdIpVK0aNECffr0AQCoqfFXkIiIqKzwGrsy8jFeY2dpaYkZM2bA399fLPv222/xyy+/4ObNm2JZQai7d+8ejh07hqpVqxbb78OHD2FpaYkzZ87A1dVVLM/Ly0NiYiKMjY0RERGBzp07Izk5GcbGxmU/OSoUr7ErHq+xI6LKqDQZ452/K5Y+fi9evFA6Yqauro78/HzxeUGou337No4fP/7WUAdA3D4rK0up7+rVqwMAfv31V7i6ujLUERERlSEGu09Y165d8d1338HKygr169fHxYsXsWzZMgwZMgTAq1DXs2dPXLhwAWFhYeIRNwAwMjKCVCrF33//jaioKLRu3RqGhoa4e/cuZs+eDVtbW/Fo3X///YedO3fCzc0NmZmZCA4ORmhoKE6ePFlhcyciIlJFDHafsNWrV2P27NkYPXo0kpOTYWFhgREjRmDOnDkAgH///Rf79u0DADg5OSlse/z4cbi5uUFHRwe7du3C3LlzkZGRAXNzc3Tq1AmzZs2CTCYT22/ZsgVTpkyBIAhwdXXFiRMn0KxZsw82VyIiok8Br7ErIx/jNXb06eE1dsXjNXZEVBlxHTsiIiKiTxCDHREREZGK4DV2H5maM/ZX9BAqtbiFXhU9BCIiogrDI3ZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqi0ge7mjVrQiKRKD38/f0BAG5ubkp1I0eOVOgjPj4eXl5e0NHRgYmJCaZOnYrc3FyFNidOnEDjxo0hk8lQu3ZthISEfKgpEhEREZWJSv+VYlFRUcjLyxOfX716FZ9//jl69eollg0bNgzz5s0Tn+vo6Ig/5+XlwcvLC2ZmZjhz5gwSEhIwcOBAaGpqYsGCBQCA2NhYeHl5YeTIkdi6dSsiIiIwdOhQmJubw8PD4wPMkoiIiOj9VfpgZ2xsrPB84cKFsLW1Rdu2bcUyHR0dmJmZFbr9kSNHcP36dRw9ehSmpqZwcnLC/PnzMX36dAQEBEAqlWLDhg2wsbHB0qVLAQD29vY4ffo0li9fzmBHREREH41Kfyr2ddnZ2fjll18wZMgQSCQSsXzr1q2oVq0aGjRogJkzZ+LFixdiXWRkJBwdHWFqaiqWeXh4IC0tDdeuXRPbuLu7K+zLw8MDkZGRRY4lKysLaWlpCg8iIiKiilTpj9i9bs+ePUhJScGgQYPEsn79+sHa2hoWFha4fPkypk+fjlu3bmHXrl0AgMTERIVQB0B8npiYWGybtLQ0vHz5Etra2kpjCQoKQmBgYFlOj4iIiOi9fFTBbtOmTfD09ISFhYVYNnz4cPFnR0dHmJubo0OHDrh79y5sbW3LbSwzZ87EpEmTxOdpaWmwtLQst/0RERERvc1HE+zu37+Po0ePikfiitK8eXMAwJ07d2BrawszMzOcO3dOoU1SUhIAiNflmZmZiWWvt5HL5YUerQMAmUwGmUz2TnMhIiIiKg8fzTV2wcHBMDExgZeXV7HtYmJiAADm5uYAAFdXV1y5cgXJyclim/DwcMjlcjg4OIhtIiIiFPoJDw+Hq6trGc6AiIiIqHx9FMEuPz8fwcHB8PX1hYbG/z/IePfuXcyfPx/R0dGIi4vDvn37MHDgQLRp0wYNGzYEAHTs2BEODg4YMGAALl26hMOHD2PWrFnw9/cXj7iNHDkS9+7dw7Rp03Dz5k2sW7cOO3bswMSJEytkvkRERETv4qMIdkePHkV8fDyGDBmiUC6VSnH06FF07NgRdnZ2mDx5Mnx8fPDHH3+IbdTV1REWFgZ1dXW4urriq6++wsCBAxXWvbOxscH+/fsRHh6ORo0aYenSpfjxxx+51AkRERF9VD6Ka+w6duwIQRCUyi0tLXHy5Mm3bm9tbY0DBw4U28bNzQ0XL1585zESERERVbSP4ogdEREREb0dgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiEhFMNgRERERqQgGOyIiIiIVwWBHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiD6ogIAASCQShYednZ1Yn5mZCX9/f1StWhW6urrw8fFBUlKSQh9vbi+RSLB9+3axftCgQYW2qV+//gebZ0VgsCMiIqIPrn79+khISBAfp0+fFusmTpyIP/74A6GhoTh58iQePXqEHj16KPURHBys0Ie3t7dYt3LlSoW6Bw8ewMjICL169foQ06swGhU9ACIiIvr0aGhowMzMTKk8NTUVmzZtwrZt29C+fXsArwKcvb09zp49ixYtWohtDQwMCu0DAPT19aGvry8+37NnD549e4bBgweX8UwqFx6xIyIiog/u9u3bsLCwQK1atdC/f3/Ex8cDAKKjo5GTkwN3d3exrZ2dHaysrBAZGanQh7+/P6pVq4ZmzZph8+bNEAShyP1t2rQJ7u7usLa2Lp8JVRI8YkdEREQfVPPmzRESEoJ69eohISEBgYGB+Oyzz3D16lUkJiZCKpXCwMBAYRtTU1MkJiaKz+fNm4f27dtDR0cHR44cwejRo5Geno5x48Yp7e/Ro0c4ePAgtm3bVt5Tq3AMdkRERPRBeXp6ij83bNgQzZs3h7W1NXbs2AFtbe0S9TF79mzxZ2dnZ2RkZGDx4sWFBrstW7bAwMBA4Ro8VcVTsURERFShDAwMULduXdy5cwdmZmbIzs5GSkqKQpukpKQir6cDXh0FfPjwIbKyshTKBUHA5s2bMWDAAEil0vIYfqXCYEdEREQVKj09HXfv3oW5uTlcXFygqamJiIgIsf7WrVuIj4+Hq6trkX3ExMTA0NAQMplMofzkyZO4c+cO/Pz8ym38lQlPxRIREdEHNWXKFHTt2hXW1tZ49OgR5s6dC3V1dfTt2xf6+vrw8/PDpEmTYGRkBLlcjrFjx8LV1VW8I/aPP/5AUlISWrRoAS0tLYSHh2PBggWYMmWK0r42bdqE5s2bo0GDBh96mhWCwY6IiIg+qIcPH6Jv37548uQJjI2N0bp1a5w9exbGxsYAgOXLl0NNTQ0+Pj7IysqCh4cH1q1bJ26vqamJtWvXYuLEiRAEAbVr18ayZcswbNgwhf2kpqbi999/x8qVKz/o/CpSpT4VWxYrU8fHx8PLyws6OjowMTHB1KlTkZubq9DmxIkTaNy4MWQyGWrXro2QkJAPMT0iIqJP0vbt2/Ho0SNkZWXh4cOH2L59O2xtbcV6LS0trF27Fk+fPkVGRgZ27dqlcH1dp06dcPHiRTx//hzp6emIiYnBiBEjoKamGGv09fXx4sULpcCnyip1sAPeb2XqvLw8eHl5ITs7G2fOnMGWLVsQEhKCOXPmiG1iY2Ph5eWFdu3aISYmBhMmTMDQoUNx+PDhDzpPIiIiovdV6U/Fvs/K1EeOHMH169dx9OhRmJqawsnJCfPnz8f06dMREBAAqVSKDRs2wMbGBkuXLgUA2Nvb4/Tp01i+fDk8PDw+6FyJiIiI3kelD3YFK1NraWnB1dUVQUFBsLKyeuvK1C1atEBkZCQcHR1hamoqtvHw8MCoUaNw7do1ODs7IzIyUqGPgjYTJkz4UFMkIiKq1By3OFb0ECq9K75XKnoIACp5sHvflakTExMVQl1BfUFdcW3S0tLw8uXLIhdKzMrKUlgrJy0t7b3mSkRERPS+KnWwK4uVqctLUFAQAgMDK3QMRERERK+r9DdPvK60K1ObmZkp3SVb8PxtbeRyebHhcebMmUhNTRUfDx48eN/pEREREb2XjyrYlXZlaldXV1y5cgXJyclim/DwcMjlcjg4OIhtXu+joE1xq1sDgEwmg1wuV3gQERERVaRKHeymTJmCkydPIi4uDmfOnEH37t0LXZn6+PHjiI6OxuDBgxVWpu7YsSMcHBwwYMAAXLp0CYcPH8asWbPg7+8vfuXIyJEjce/ePUybNg03b97EunXrsGPHDkycOLEip05ERERUapX6Grv3XZlaXV0dYWFhGDVqFFxdXVGlShX4+vpi3rx5YhsbGxvs378fEydOxMqVK1GjRg38+OOPXOqEiIiIPjoSQRCEih6EKkhLS4O+vj5SU1PL9bRszRn7y61vVRC30Kuih1CpccmC4lWW5QqIKht+drxdeX5+lCZjVOpTsURERERUcgx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZEREREKoLBjoiIiEhFMNgRFWP9+vVo2LAh5HI55HI5XF1dcfDgQbE+MzMT/v7+qFq1KnR1deHj44OkpKRC+3ry5Alq1KgBiUSClJQUsTwhIQH9+vVD3bp1oaamhgkTJpTzrIiISFUx2BEVo0aNGli4cCGio6Nx/vx5tG/fHt26dcO1a9cAABMnTsQff/yB0NBQnDx5Eo8ePUKPHj0K7cvPzw8NGzZUKs/KyoKxsTFmzZqFRo0alet8iIhItWlU9ACIKrOuXbsqPP/uu++wfv16nD17FjVq1MCmTZuwbds2tG/fHgAQHBwMe3t7nD17Fi1atBC3W79+PVJSUjBnzhyFI34AULNmTaxcuRIAsHnz5nKeERERqTIesSMqoby8PGzfvh0ZGRlwdXVFdHQ0cnJy4O7uLraxs7ODlZUVIiMjxbLr169j3rx5+Omnn6Cmxj85IiIqP/xXhugtrly5Al1dXchkMowcORK7d++Gg4MDEhMTIZVKYWBgoNDe1NQUiYmJAF6dZu3bty8WL14MKyurChg9ERF9Sngqlugt6tWrh5iYGKSmpmLnzp3w9fXFyZMnS7TtzJkzYW9vj6+++qqcR0lERMQjdkRvJZVKUbt2bbi4uCAoKAiNGjXCypUrYWZmhuzsbIU7XAEgKSkJZmZmAIBjx44hNDQUGhoa0NDQQIcOHQAA1apVw9y5cz/0VIiISMXxiB1RKeXn5yMrKwsuLi7Q1NREREQEfHx8AAC3bt1CfHw8XF1dAQC///47Xr58KW4bFRWFIUOG4M8//4StrW2FjJ+IiFQXgx1RMWbOnAlPT09YWVnh+fPn2LZtG06cOIHDhw9DX18ffn5+mDRpEoyMjCCXyzF27Fi4urqKd8S+Gd7+++8/AIC9vb3CtXkxMTEAgPT0dDx+/BgxMTGQSqVwcHD4IPMkIiLVwGBHVIzk5GQMHDgQCQkJ0NfXR8OGDXH48GF8/vnnAIDly5dDTU0NPj4+yMrKgoeHB9atW1fq/Tg7O4s/R0dHY9u2bbC2tkZcXFxZTYWIiD4BDHZExdi0aVOx9VpaWli7di3Wrl1bov7c3NwgCIJSeWFlREREpcWbJ4iIiIhUBIMdERERkYrgqVhSLQH6FT2Cys2GiyQTEakyHrEjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhVRqYNdUFAQmjZtCj09PZiYmMDb2xu3bt1SaOPm5gaJRKLwGDlypEKb+Ph4eHl5QUdHByYmJpg6dSpyc3MV2pw4cQKNGzeGTCZD7dq1ERISUt7TIyIiIipTlTrYnTx5Ev7+/jh79izCw8ORk5ODjh07IiMjQ6HdsGHDkJCQID4WLVok1uXl5cHLywvZ2dk4c+YMtmzZgpCQEMyZM0dsExsbCy8vL7Rr1w4xMTGYMGEChg4disOHD3+wuRIRERG9r0q9jt2hQ4cUnoeEhMDExATR0dFo06aNWK6jowMzM7NC+zhy5AiuX7+Oo0ePwtTUFE5OTpg/fz6mT5+OgIAASKVSbNiwATY2Nli6dCmAV1/Qfvr0aSxfvhweHh7lN0EiIiKiMlSpj9i9KTU1FQBgZGSkUL5161ZUq1YNDRo0wMyZM/HixQuxLjIyEo6OjjA1NRXLPDw8kJaWhmvXrolt3N3dFfr08PBAZGRkeU2FiIiIqMxV6iN2r8vPz8eECRPQqlUrNGjQQCzv168frK2tYWFhgcuXL2P69Om4desWdu3aBQBITExUCHUAxOeJiYnFtklLS8PLly+hra2tNJ6srCxkZWWJz9PS0spmokRERETv6KMJdv7+/rh69SpOnz6tUD58+HDxZ0dHR5ibm6NDhw64e/cubG1ty208QUFBCAwMLLf+iYiIiErrozgVO2bMGISFheH48eOoUaNGsW2bN28OALhz5w4AwMzMDElJSQptCp4XXJdXVBu5XF7o0ToAmDlzJlJTU8XHgwcPSj8xIiIiojJUqYOdIAgYM2YMdu/ejWPHjsHGxuat28TExAAAzM3NAQCurq64cuUKkpOTxTbh4eGQy+VwcHAQ20RERCj0Ex4eDldX1yL3I5PJIJfLFR5EREREFalSBzt/f3/88ssv2LZtG/T09JCYmIjExES8fPkSAHD37l3Mnz8f0dHRiIuLw759+zBw4EC0adMGDRs2BAB07NgRDg4OGDBgAC5duoTDhw9j1qxZ8Pf3h0wmAwCMHDkS9+7dw7Rp03Dz5k2sW7cOO3bswMSJEyts7kRERESlVamD3fr165Gamgo3NzeYm5uLj99++w0AIJVKcfToUXTs2BF2dnaYPHkyfHx88Mcff4h9qKurIywsDOrq6nB1dcVXX32FgQMHYt68eWIbGxsb7N+/H+Hh4WjUqBGWLl2KH3/8kUudEBER0UelUt88IQhCsfWWlpY4efLkW/uxtrbGgQMHim3j5uaGixcvlmp8RERERJVJpT5iR0REREQlx2BHREREpCIY7IiIiIhUBIMdERERkYpgsCMiIiJSEQx2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXBYEdERESkIhjsiIiIiFQEgx0RERGRimCwIyIiIlIRDHZERFSmFi5cCIlEggkTJijVCYIAT09PSCQS7NmzR6FOIpEoPbZv3/5hBk2kIjQqegBERKQ6oqKi8P3336Nhw4aF1q9YsQISiaTI7YODg9GpUyfxuYGBQVkPkUil8YgdERGVifT0dPTv3x8//PADDA0NlepjYmKwdOlSbN68ucg+DAwMYGZmJj60tLTKc8hEKofBjoiIyoS/vz+8vLzg7u6uVPfixQv069cPa9euhZmZWbF9VKtWDc2aNcPmzZshCEJ5DplI5fBULBERvbft27fjwoULiIqKKrR+4sSJaNmyJbp161ZkH/PmzUP79u2ho6ODI0eOYPTo0UhPT8e4cePKa9hEKofBjoiI3suDBw8wfvx4hIeHF3rqdN++fTh27BguXrxYbD+zZ88Wf3Z2dkZGRgYWL17MYEdUCjwVS0RE7yU6OhrJyclo3LgxNDQ0oKGhgZMnT2LVqlXQ0NBAeHg47t69CwMDA7EeAHx8fODm5lZkv82bN8fDhw+RlZX1gWZC9PFjsCMiovfSoUMHXLlyBTExMeKjSZMm6N+/P2JiYvDNN9/g8uXLCvUAsHz5cgQHBxfZb0xMDAwNDSGTyT7QTMrPqVOn0LVrV1hYWCgt9ZKTk4Pp06fD0dERVapUgYWFBQYOHIhHjx4p9bN//340b94c2traMDQ0hLe394ebBH0UeCqWiIjei56eHho0aKBQVqVKFVStWlUsL+yGCSsrK9jY2AAA/vjjDyQlJaFFixbQ0tJCeHg4FixYgClTppT/BD6AjIwMNGrUCEOGDEGPHj0U6l68eIELFy5g9uzZaNSoEZ49e4bx48fjiy++wPnz58V2v//+O4YNG4YFCxagffv2yM3NxdWrVz/0VKiSY7AjIqIKp6mpibVr12LixIkQBAG1a9fGsmXLMGzYsIoeWpnw9PSEp6dnoXX6+voIDw9XKFuzZg2aNWuG+Ph4WFlZITc3F+PHj8fixYvh5+cntnNwcCjXcdPHh8GOiIjK3IkTJ4qtf3MZk06dOiksTPypS01NhUQiERdovnDhAv7991+oqanB2dkZiYmJcHJywuLFi5WOltKnjdfYERERVSKZmZmYPn06+vbtC7lcDgC4d+8eACAgIACzZs1CWFgYDA0N4ebmhqdPn1bkcKmSYbAjIiKqJHJyctC7d28IgoD169eL5fn5+QCAb775Bj4+PnBxcUFwcDAkEglCQ0MrarhUCfFULBHRJ6DmjP0VPYRKLW6hV0UPQQx19+/fx7Fjx8SjdQBgbm4OQPGaOplMhlq1aiE+Pv6Dj5UqLx6xIyIiqmAFoe727ds4evQoqlatqlDv4uICmUyGW7duKWwTFxcHa2vrDz1cqsR4xI6IiKicpaen486dO+Lz2NhYxMTEwMjICObm5ujZsycuXLiAsLAw5OXlITExEQBgZGQEqVQKuVyOkSNHYu7cubC0tIS1tTUWL14MAOjVq1eFzIkqJwY7IiKicnb+/Hm0a9dOfD5p0iQAgK+vLwICArBv3z4AgJOTk8J2x48fF7+dY/HixdDQ0MCAAQPw8uVLNG/eHMeOHYOhoeEHmQN9HBjsiIiIypmbm5vSEi+vK66ugKamJpYsWYIlS5aU5dBIxfAauzesXbsWNWvWhJaWFpo3b45z585V9JCIiIiISoTB7jW//fYbJk2ahLlz5+LChQto1KgRPDw8kJycXNFDIyIiInornop9TcHX1wwePBgAsGHDBuzfvx+bN2/GjBkzKnh0RERUbgL0K3oElZuNVUWPgEqIwe7/ZGdnIzo6GjNnzhTL1NTU4O7ujsjISKX2WVlZyMrKEp+npqYCANLS0sp1nPlZL8q1/49dmuTt16l8yvJe5lX0ECq18v77rUj87CgePzuKx8+OtyvPz4+CvktyLSaD3f/577//kJeXB1NTU4VyU1NT3Lx5U6l9UFAQAgMDlcotLS3LbYz0dvx/7re5UdEDqNT0R/E36FPFd/5t+NnxNh/i8+P58+fQ1y9+Pwx272jmzJni7erAq697efr0KapWrQqJRFKBI6PKIi0tDZaWlnjw4IHCCvJERMXhZwe9SRAEPH/+HBYWFm9ty2D3f6pVqwZ1dXUkJSUplCclJcHMzEypvUwmg0wmUygzMDAozyHSR0oul/PDmYhKjZ8d9Lq3HakrwLti/49UKoWLiwsiIiLEsvz8fERERMDV1bUCR0ZERERUMjxi95pJkybB19cXTZo0QbNmzbBixQpkZGSId8kSERERVWYMdq/58ssv8fjxY8yZMweJiYlwcnLCoUOHlG6oICoJmUyGuXPnKp2yJyIqDj876H1IhJLcO0tERERElR6vsSMiIiJSEQx2RERERCqCwY6IiIhIRTDYERUiICAATk5OxbYZNGgQvL29xedubm6YMGFCsduEhIRwvUOiT0xJPk9K4s3PHKLCMNjRJyMyMhLq6urw8vIql/537dqF+fPni89r1qyJFStWKLT58ssv8c8//5TL/omobA0aNAgSiQQSiQSampowNTXF559/js2bNyM/P7/c9hsXFweJRIKYmBiF8pUrVyIkJKTc9kuqgcGOPhmbNm3C2LFjcerUKTx69KjM+zcyMoKenl6xbbS1tWFiYlLm+yai8tGpUyckJCQgLi4OBw8eRLt27TB+/Hh06dIFubm5H3Qs+vr6POJPb8VgR5+E9PR0/Pbbbxg1ahS8vLyU/q934cKFMDU1hZ6eHvz8/JCZmalQn5eXh0mTJsHAwABVq1bFtGnT8OZKQa+finVzc8P9+/cxceJE8f/4gcJPxa5fvx62traQSqWoV68efv75Z4V6iUSCH3/8Ed27d4eOjg7q1KmDffv2ifXPnj1D//79YWxsDG1tbdSpUwfBwcHv8WoRUQGZTAYzMzNUr14djRs3xtdff429e/fi4MGD4udISkoKhg4dCmNjY8jlcrRv3x6XLl0qtt8ff/wR9vb20NLSgp2dHdatWyfW2djYAACcnZ0hkUjg5uYGQPlUbFZWFsaNGwcTExNoaWmhdevWiIqKEutPnDgBiUSCiIgINGnSBDo6OmjZsiVu3boltrl06RLatWsHPT09yOVyuLi44Pz58+/5qlFFYrCjT8KOHTtgZ2eHevXq4auvvsLmzZvFYLZjxw4EBARgwYIFOH/+PMzNzRU+ZAFg6dKlCAkJwebNm3H69Gk8ffoUu3fvLnJ/u3btQo0aNTBv3jwkJCQgISGh0Ha7d+/G+PHjMXnyZFy9ehUjRozA4MGDcfz4cYV2gYGB6N27Ny5fvozOnTujf//+ePr0KQBg9uzZuH79Og4ePIgbN25g/fr1qFat2vu8XERUjPbt26NRo0bYtWsXAKBXr15ITk7GwYMHER0djcaNG6NDhw7i3+ibtm7dijlz5uC7777DjRs3sGDBAsyePRtbtmwBAJw7dw4AcPToUSQkJIj7edO0adPw+++/Y8uWLbhw4QJq164NDw8Ppf1+8803WLp0Kc6fPw8NDQ0MGTJErOvfvz9q1KiBqKgoREdHY8aMGdDU1Hzv14gqkED0CWjZsqWwYsUKQRAEIScnR6hWrZpw/PhxQRAEwdXVVRg9erRC++bNmwuNGjUSn5ubmwuLFi0Sn+fk5Ag1atQQunXrJpa1bdtWGD9+vPjc2tpaWL58uUK/wcHBgr6+vsK4hg0bptCmV69eQufOncXnAIRZs2aJz9PT0wUAwsGDBwVBEISuXbsKgwcPfutrQESl4+vrq/A3/rovv/xSsLe3F/78809BLpcLmZmZCvW2trbC999/LwiCIMydO1fh88TW1lbYtm2bQvv58+cLrq6ugiAIQmxsrABAuHjxYpHjSU9PFzQ1NYWtW7eK9dnZ2YKFhYX4WXX8+HEBgHD06FGxzf79+wUAwsuXLwVBEAQ9PT0hJCSkZC8IfRR4xI5U3q1bt3Du3Dn07dsXAKChoYEvv/wSmzZtAgDcuHEDzZs3V9jG1dVV/Dk1NRUJCQkKbTQ0NNCkSZP3HtuNGzfQqlUrhbJWrVrhxo0bCmUNGzYUf65SpQrkcjmSk5MBAKNGjcL27dvh5OSEadOm4cyZM+89LiIqniAIkEgkuHTpEtLT01G1alXo6uqKj9jYWNy9e1dpu4yMDNy9exd+fn4K7b/99ttC2xfl7t27yMnJUfj80NTURLNmzYr9/DA3NwcA8fNj0qRJGDp0KNzd3bFw4cJSjYEqJ35XLKm8TZs2ITc3FxYWFmKZIAiQyWRYs2ZNBY6s5N48NSKRSMS78jw9PXH//n0cOHAA4eHh6NChA/z9/bFkyZKKGCrRJ+HGjRuwsbFBeno6zM3NceLECaU2hd3okJ6eDgD44YcflP6HUl1dvTyGqvD5UXC9b8HnR0BAAPr164f9+/fj4MGDmDt3LrZv347u3buXy1io/PGIHam03Nxc/PTTT1i6dCliYmLEx6VLl2BhYYFff/0V9vb2+PvvvxW2O3v2rPizvr4+zM3NFdrk5uYiOjq62H1LpVLk5eUV28be3h5//fWXQtlff/0FBweHkk4RAGBsbAxfX1/88ssvWLFiBTZu3Fiq7Ymo5I4dO4YrV67Ax8cHjRs3RmJiIjQ0NFC7dm2FR2HXupqamsLCwgL37t1Tal9w04RUKgWAYj8/Cm64ev3zIycnB1FRUaX+/Khbty4mTpyII0eOoEePHrz56iPHI3ak0sLCwvDs2TP4+flBX19foc7HxwebNm3ClClTMGjQIDRp0gStWrXC1q1bce3aNdSqVUtsO378eCxcuBB16tSBnZ0dli1bhpSUlGL3XbNmTZw6dQp9+vSBTCYr9EN+6tSp6N27N5ydneHu7o4//vgDu3btwtGjR0s8xzlz5sDFxQX169dHVlYWwsLCYG9vX+LtiahoWVlZSExMRF5eHpKSknDo0CEEBQWhS5cuGDhwINTU1ODq6gpvb28sWrQIdevWxaNHj7B//35079690Es2AgMDMW7cOOjr66NTp07IysrC+fPn8ezZM0yaNAkmJibQ1tbGoUOHUKNGDWhpaSl9flWpUgWjRo3C1KlTYWRkBCsrKyxatAgvXryAn59fieb28uVLTJ06FT179oSNjQ0ePnyIqKgo+Pj4lMlrRxWDR+xIpW3atAnu7u5KH4rAq2B3/vx52NvbY/bs2Zg2bRpcXFxw//59jBo1SqHt5MmTMWDAAPj6+sLV1RV6enpvPVUxb948xMXFwdbWFsbGxoW28fb2xsqVK7FkyRLUr18f33//PYKDg8XlDUpCKpVi5syZaNiwIdq0aQN1dXVs3769xNsTUdEOHToEc3Nz1KxZE506dcLx48exatUq7N27F+rq6pBIJDhw4ADatGmDwYMHo27duujTpw/u378PU1PTQvscOnQofvzxRwQHB8PR0RFt27ZFSEiIeMROQ0MDq1atwvfffw8LCwt069at0H4WLlwIHx8fDBgwAI0bN8adO3dw+PBhGBoalmhu6urqePLkCQYOHIi6deuid+/e8PT0RGBg4Lu9WFQpSAThjcW4iIiIiOijxCN2RERERCqCwY6IiIhIRTDYEREREakIBjsiIiIiFcFgR0RERKQiGOyIiIiIVASDHREREZGKYLAjIiIiUhEMdkREREQqgsGOiIiISEUw2BERERGpCAY7IiIiIhXx/wDda/oNJ3A+FAAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "krishna_summary_2 = github_utils.summarize_repo_metrics_for_user(\n",
+ " combined,\n",
+ " user=\"tkpratardan\",\n",
+ ")\n",
+ "\n",
+ "github_utils.plot_metrics_by_repo(\n",
+ " krishna_summary_2,\n",
+ " user=\"tkpratardan\",\n",
+ " metrics=['additions', 'deletions'],\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "94679d8c-745d-4679-b44d-e2f04951d8cb",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "INFO:github_utils:Generated 144 days in period.\n",
+ "INFO:github_utils:Built daily commit DataFrame rows=144.\n"
+ ]
+ }
+ ],
+ "source": [
+ "krishna_daily_commits = github_utils.build_daily_commit_df(\n",
+ " client, org=\"causify-ai\",\n",
+ " repo=\"helpers\",\n",
+ " username=\"tkpratardan\",\n",
+ " period=(datetime.datetime(2025,1,1, tzinfo=datetime.timezone.utc),\n",
+ " datetime.datetime(2025,5,24, tzinfo=datetime.timezone.utc)),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "74b56187-49d3-4213-8d52-73dd0d2004ab",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " date | \n",
+ " commits | \n",
+ " repo | \n",
+ " user | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2025-01-01 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2025-01-02 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2025-01-03 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2025-01-04 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2025-01-05 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 2025-01-06 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 2025-01-07 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 2025-01-08 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 2025-01-09 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2025-01-10 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 2025-01-11 | \n",
+ " 1 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 2025-01-12 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " 2025-01-13 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " 2025-01-14 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " 2025-01-15 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " 2025-01-16 | \n",
+ " 1 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " 2025-01-17 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " 2025-01-18 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " 2025-01-19 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " 2025-01-20 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 20 | \n",
+ " 2025-01-21 | \n",
+ " 1 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 21 | \n",
+ " 2025-01-22 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 22 | \n",
+ " 2025-01-23 | \n",
+ " 1 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 23 | \n",
+ " 2025-01-24 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ " | 24 | \n",
+ " 2025-01-25 | \n",
+ " 0 | \n",
+ " helpers | \n",
+ " tkpratardan | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " date commits repo user\n",
+ "0 2025-01-01 0 helpers tkpratardan\n",
+ "1 2025-01-02 0 helpers tkpratardan\n",
+ "2 2025-01-03 0 helpers tkpratardan\n",
+ "3 2025-01-04 0 helpers tkpratardan\n",
+ "4 2025-01-05 0 helpers tkpratardan\n",
+ "5 2025-01-06 0 helpers tkpratardan\n",
+ "6 2025-01-07 0 helpers tkpratardan\n",
+ "7 2025-01-08 0 helpers tkpratardan\n",
+ "8 2025-01-09 0 helpers tkpratardan\n",
+ "9 2025-01-10 0 helpers tkpratardan\n",
+ "10 2025-01-11 1 helpers tkpratardan\n",
+ "11 2025-01-12 0 helpers tkpratardan\n",
+ "12 2025-01-13 0 helpers tkpratardan\n",
+ "13 2025-01-14 0 helpers tkpratardan\n",
+ "14 2025-01-15 0 helpers tkpratardan\n",
+ "15 2025-01-16 1 helpers tkpratardan\n",
+ "16 2025-01-17 0 helpers tkpratardan\n",
+ "17 2025-01-18 0 helpers tkpratardan\n",
+ "18 2025-01-19 0 helpers tkpratardan\n",
+ "19 2025-01-20 0 helpers tkpratardan\n",
+ "20 2025-01-21 1 helpers tkpratardan\n",
+ "21 2025-01-22 0 helpers tkpratardan\n",
+ "22 2025-01-23 1 helpers tkpratardan\n",
+ "23 2025-01-24 0 helpers tkpratardan\n",
+ "24 2025-01-25 0 helpers tkpratardan"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "krishna_daily_commits[0:25]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6d1814db-b00f-4d7f-b39d-4568a5abeb4c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## There are many more helper funcs to see and compare statistics. Look at github_utils for more info -> `tutorial_github_causify_style/github_utils.py`"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}