diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 668bb5aceb..06213bdf40 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,5 +4,5 @@ # It uses the same pattern rule for gitignore file # https://git-scm.com/docs/gitignore#_pattern_format - -garbage_collector.rst @pablogsal +# PSRT member list owned by PSRT admins. +developer-workflow/psrt*.csv @warsaw @ewdurbin @ned-deily @sethmlarson diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 218b07b63b..c4a7d25457 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,13 +18,12 @@ Please be aware that our workflow does deviate slightly from the typical GitHub project. Details on how to properly submit a pull request are covered in [Lifecycle of a Pull Request](https://devguide.python.org/pullrequest/). We utilize various bots and status checks to help with this, so do follow the -comments they leave and their "Details" links, respectively. The key points of -our workflow that are not covered by a bot or status check are: +comments they leave and their "Details" links, respectively. -- All discussions that are not directly related to the code in the pull request - should happen on the [issue tracker](https://devguide.python.org/tracker/) -- Upon your first non-trivial pull request (which includes documentation changes), - feel free to add yourself to [`Misc/ACKS`](https://github.com/python/cpython/blob/main/Misc/ACKS) +The final key part of our workflow is that all discussions that are not +directly related to the code in the pull request should happen on the +[issue tracker](https://devguide.python.org/tracker/), generally in the +pull request's parent issue. ## Setting Expectations @@ -33,8 +32,8 @@ Due to the fact that this project is entirely volunteer-run (that is, no one is to work on Python full-time), we unfortunately can make no guarantees as to if or when a core developer will get around to reviewing your pull request. If no core developer has done a review or responded to changes made because of a -"changes requested" review, please feel free to email [python-dev](https://mail.python.org/mailman3/lists/python-dev.python.org/) to ask if -someone could take a look at your pull request. +"changes requested" review, please consider seeking assistance through the +[Core Development Discourse category](https://discuss.python.org/c/core-dev/23). ## Code of Conduct diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b160c6ea11..f6d55b1247 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,7 @@ name: "Bug report" description: Create a report to help us improve the Python devguide title: "Bug: " -labels: ["bug"] +labels: ["type-bug"] assignees: [] body: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index a4413c137a..7a7e9ec805 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: "Feature request" description: Suggest an idea for the Python devguide title: "Feature: <title>" -labels: ["enhancement"] +labels: ["type-feature"] assignees: [] body: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c990752808..23f03616cf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,23 @@ version: 2 updates: +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: monthly + assignees: + - "ezio-melotti" + groups: + actions: + patterns: + - "*" + - package-ecosystem: pip directory: "/" schedule: interval: monthly - open-pull-requests-limit: 10 + assignees: + - "ezio-melotti" + groups: + pip: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22ad254ebf..b85a45c1bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3" - name: Install uv diff --git a/.github/workflows/documentation-links.yml b/.github/workflows/documentation-links.yml deleted file mode 100644 index bacb37d07c..0000000000 --- a/.github/workflows/documentation-links.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Read the Docs PR preview -on: - pull_request_target: - types: - - opened - -permissions: - pull-requests: write - -jobs: - documentation-links: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: readthedocs/actions/preview@v1 - with: - project-slug: "cpython-devguide" - single-version: "true" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5c9caf026f..4622f995aa 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,8 +8,8 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.x" - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 diff --git a/.gitignore b/.gitignore index df4dc9415a..f61a108300 100644 --- a/.gitignore +++ b/.gitignore @@ -90,4 +90,5 @@ celerybeat-schedule # Generated CSV and SVG files include/branches.csv include/end-of-life.csv -include/release-cycle.svg +_static/release-cycle.svg +_static/release-cycle-all.svg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae27fd1f23..c5beee4a37 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,14 +7,12 @@ repos: args: [--exit-non-zero-on-fix] - id: ruff-format name: Run Ruff (format) - args: [--check] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-case-conflict - id: check-merge-conflict - - id: check-json - id: check-yaml - id: debug-statements - id: end-of-file-fixer diff --git a/Makefile b/Makefile index 5a33d50897..a26ad48e00 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ SPHINXBUILD = $(VENVDIR)/bin/sphinx-build # there are duplicate labels. These cause warnings, which prevent the # build from finishing. Turn off --fail-on-warning so we can see the # finished results. -#SPHINXOPTS = --fail-on-warning --keep-going -SPHINXOPTS = --keep-going +#SPHINXOPTS = --fail-on-warning +SPHINXOPTS = BUILDDIR = _build BUILDER = html JOBS = auto @@ -22,7 +22,8 @@ REQUIREMENTS = requirements.txt _ALL_SPHINX_OPTS = --jobs $(JOBS) $(SPHINXOPTS) _RELEASE_CYCLE = include/branches.csv \ include/end-of-life.csv \ - include/release-cycle.svg + _static/release-cycle-all.svg \ + _static/release-cycle.svg .PHONY: help help: @@ -57,6 +58,7 @@ venv: .PHONY: ensure-venv ensure-venv: @if [ ! -d $(VENVDIR) ] ; then \ + set -e; \ echo "Creating venv in $(VENVDIR)"; \ if $(UV) --version >/dev/null 2>&1; then \ $(UV) venv --python=$(PYTHON) $(VENVDIR); \ @@ -101,15 +103,20 @@ _ensure-pre-commit: lint: _ensure-pre-commit $(VENVDIR)/bin/python3 -m pre_commit run --all-files -# Defined so that "include/release-cycle.json" -# doesn't fall through to the catch-all target. -include/release-cycle.json: - @exit - -$(_RELEASE_CYCLE): include/release-cycle.json +# Generate all release cycle files together with a single script invocation +# Use branches.csv as the primary target, others depend on it +include/branches.csv: $(VENVDIR)/bin/python3 _tools/generate_release_cycle.py @echo Release cycle data generated. +# Other files are generated together with branches.csv +include/end-of-life.csv: include/branches.csv + @: +_static/release-cycle-all.svg: include/branches.csv + @: +_static/release-cycle.svg: include/branches.csv + @: + # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. .PHONY: Makefile diff --git a/README.rst b/README.rst index fde4a6c277..e2f0c5617c 100644 --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ The CPython Developer's Guide This guide covers how to contribute to CPython. It is known by the -nickname of "the devguide" by the Python core developers. +nickname of "the devguide" by the Python core team. The official home of this guide is https://devguide.python.org. diff --git a/_static/devguide_overrides.css b/_static/devguide_overrides.css index 8e2c7c6fca..625a9dda2d 100644 --- a/_static/devguide_overrides.css +++ b/_static/devguide_overrides.css @@ -6,79 +6,6 @@ height: 110px; } -/* Release cycle chart */ - -.release-cycle-chart { - width: 100%; -} - -.release-cycle-chart .release-cycle-year-line { - stroke: var(--color-foreground-primary); - stroke-width: 0.8px; - opacity: 75%; -} - -.release-cycle-chart .release-cycle-year-text { - fill: var(--color-foreground-primary); -} - -.release-cycle-chart .release-cycle-today-line { - stroke: var(--color-brand-primary); - stroke-width: 1.6px; -} - -.release-cycle-chart .release-cycle-row-shade { - fill: var(--color-background-item); - opacity: 50%; -} - -.release-cycle-chart .release-cycle-version-label { - fill: var(--color-foreground-primary); -} - -.release-cycle-chart .release-cycle-blob { - stroke-width: 1.6px; - /* default colours, overridden below for individual statuses */ - fill: var(--color-background-primary); - stroke: var(--color-foreground-primary); -} - -.release-cycle-chart .release-cycle-blob-label { - /* white looks good on both light & dark */ - fill: white; -} - -.release-cycle-chart .release-cycle-blob-label.release-cycle-blob-security, -.release-cycle-chart .release-cycle-blob-label.release-cycle-blob-bugfix { - /* but use black to improve contrast for lighter backgrounds */ - fill: black; -} - -.release-cycle-chart .release-cycle-blob.release-cycle-blob-end-of-life { - fill: #DD2200; - stroke: #FF8888; -} - -.release-cycle-chart .release-cycle-blob.release-cycle-blob-security { - fill: #FFDD44; - stroke: #FF8800; -} - -.release-cycle-chart .release-cycle-blob.release-cycle-blob-bugfix { - fill: #00DD22; - stroke: #008844; -} - -.release-cycle-chart .release-cycle-blob.release-cycle-blob-prerelease { - fill: teal; - stroke: darkgreen; -} - -.release-cycle-chart .release-cycle-blob.release-cycle-blob-feature { - fill: #2222EE; - stroke: #008888; -} - .good pre { border-left: 3px solid rgba(74, 182, 93, 1); } diff --git a/_static/python-cyclic-gc-1-new-page.png b/_static/python-cyclic-gc-1-new-page.png deleted file mode 100644 index 2ddac50f4b..0000000000 Binary files a/_static/python-cyclic-gc-1-new-page.png and /dev/null differ diff --git a/_static/python-cyclic-gc-2-new-page.png b/_static/python-cyclic-gc-2-new-page.png deleted file mode 100644 index 159aeeb050..0000000000 Binary files a/_static/python-cyclic-gc-2-new-page.png and /dev/null differ diff --git a/_static/python-cyclic-gc-3-new-page.png b/_static/python-cyclic-gc-3-new-page.png deleted file mode 100644 index 29fab0498e..0000000000 Binary files a/_static/python-cyclic-gc-3-new-page.png and /dev/null differ diff --git a/_static/python-cyclic-gc-4-new-page.png b/_static/python-cyclic-gc-4-new-page.png deleted file mode 100644 index 51a2b1065e..0000000000 Binary files a/_static/python-cyclic-gc-4-new-page.png and /dev/null differ diff --git a/_static/python-cyclic-gc-5-new-page.png b/_static/python-cyclic-gc-5-new-page.png deleted file mode 100644 index fe67a6896f..0000000000 Binary files a/_static/python-cyclic-gc-5-new-page.png and /dev/null differ diff --git a/_templates/page.html b/_templates/page.html new file mode 100644 index 0000000000..d1c9a515a4 --- /dev/null +++ b/_templates/page.html @@ -0,0 +1,8 @@ +{% extends "!page.html" %} + +{% block extrahead %} +{{ super() }} +{% if not is_deployment_preview %} +<script defer data-domain="devguide.python.org" src="https://analytics.python.org/js/script.outbound-links.js"></script> +{% endif %} +{% endblock %} diff --git a/_tools/generate_release_cycle.py b/_tools/generate_release_cycle.py index 3a8fefec02..24dfa03e74 100644 --- a/_tools/generate_release_cycle.py +++ b/_tools/generate_release_cycle.py @@ -3,9 +3,13 @@ from __future__ import annotations import argparse +import calendar import csv import datetime as dt import json +from functools import cache +from pathlib import Path +from urllib.request import urlopen import jinja2 @@ -18,31 +22,83 @@ def csv_date(date_str: str, now_str: str) -> str: return date_str -def parse_date(date_str: str) -> dt.date: +def parse_date(date_str: str, *, last: bool = False) -> dt.date: if len(date_str) == len("yyyy-mm"): # We need a full yyyy-mm-dd, so let's approximate - return dt.date.fromisoformat(date_str + "-01") + if last: + # Last day of month + year, month = map(int, date_str.split("-")) + last_day = calendar.monthrange(year, month)[1] + return dt.date(year, month, last_day) + else: + return dt.date.fromisoformat(date_str + "-01") + return dt.date.fromisoformat(date_str) +def parse_version(ver: str) -> list[int]: + return [int(i) for i in ver["key"].split(".")] + + +@cache +def get_versions() -> dict[str, dict[str, str | int]]: + with urlopen("https://peps.python.org/api/release-cycle.json") as in_file: + return json.loads(in_file.read().decode("utf-8")) + + class Versions: """For converting JSON to CSV and SVG.""" - def __init__(self) -> None: - with open("include/release-cycle.json", encoding="UTF-8") as in_file: - self.versions = json.load(in_file) + def __init__(self, *, limit_to_active=False, special_py27=False) -> None: + self.versions = get_versions() # Generate a few additional fields for key, version in self.versions.items(): version["key"] = key - version["first_release_date"] = parse_date(version["first_release"]) - version["end_of_life_date"] = parse_date(version["end_of_life"]) + ver_info = parse_version(version) + if ver_info >= [3, 13]: + full_years = 2 + else: + full_years = 1.5 + version["first_release_date"] = r1 = parse_date(version["first_release"]) + version["start_security_date"] = r1 + dt.timedelta(days=full_years * 365) + version["end_of_life_date"] = parse_date(version["end_of_life"], last=True) + + self.cutoff = min(ver["first_release_date"] for ver in self.versions.values()) + + if limit_to_active: + self.cutoff = min( + version["first_release_date"] + for version in self.versions.values() + if version["status"] != "end-of-life" + ) + self.versions = { + key: version + for key, version in self.versions.items() + if version["end_of_life_date"] >= self.cutoff + or (special_py27 and key == "2.7") + } + if special_py27: + self.cutoff = min(self.cutoff, dt.date(2019, 8, 1)) + self.id_key = "active" + else: + self.id_key = "all" + self.sorted_versions = sorted( self.versions.values(), - key=lambda v: [int(i) for i in v["key"].split(".")], + key=parse_version, reverse=True, ) + # Set the row (Y coordinate) for the chart, to allow a gap between 2.7 + # and the rest + y = len(self.sorted_versions) + (1 if special_py27 else 0) + for version in self.sorted_versions: + if special_py27 and version["key"] == "2.7": + y -= 1 + version["y"] = y + y -= 1 + def write_csv(self) -> None: """Output CSV files.""" now_str = str(dt.datetime.now(dt.timezone.utc)) @@ -68,7 +124,7 @@ def write_csv(self) -> None: csv_file.writeheader() csv_file.writerows(versions.values()) - def write_svg(self, today: str) -> None: + def write_svg(self, today: str, out_path: str) -> None: """Output SVG file.""" env = jinja2.Environment( loader=jinja2.FileSystemLoader("_tools/"), @@ -85,6 +141,8 @@ def write_svg(self, today: str) -> None: # CSS. # (Ideally we'd actually use `em` units, but SVG viewBox doesn't take # those.) + + # Uppercase sizes are un-scaled SCALE = 18 # Width of the drawing and main parts @@ -96,7 +154,7 @@ def write_svg(self, today: str) -> None: # some positioning numbers in the template as well. LINE_HEIGHT = 1.5 - first_date = min(ver["first_release_date"] for ver in self.sorted_versions) + first_date = self.cutoff last_date = max(ver["end_of_life_date"] for ver in self.sorted_versions) def date_to_x(date: dt.date) -> float: @@ -105,7 +163,7 @@ def date_to_x(date: dt.date) -> float: total_days = (last_date - first_date).days ratio = num_days / total_days x = ratio * (DIAGRAM_WIDTH - LEGEND_WIDTH - RIGHT_MARGIN) - return x + LEGEND_WIDTH + return (x + LEGEND_WIDTH) * SCALE def year_to_x(year: int) -> float: """Convert year number to an SVG X coordinate of 1st January""" @@ -115,20 +173,21 @@ def format_year(year: int) -> str: """Format year number for display""" return f"'{year % 100:02}" - with open( - "include/release-cycle.svg", "w", encoding="UTF-8", newline="\n" - ) as f: + with open(out_path, "w", encoding="UTF-8", newline="\n") as f: template.stream( SCALE=SCALE, - diagram_width=DIAGRAM_WIDTH, - diagram_height=(len(self.sorted_versions) + 2) * LINE_HEIGHT, + diagram_width=DIAGRAM_WIDTH * SCALE, + diagram_height=(self.sorted_versions[0]["y"] + 2) * LINE_HEIGHT * SCALE, years=range(first_date.year, last_date.year + 1), - LINE_HEIGHT=LINE_HEIGHT, + line_height=LINE_HEIGHT * SCALE, + legend_width=LEGEND_WIDTH * SCALE, + right_margin=RIGHT_MARGIN * SCALE, versions=list(reversed(self.sorted_versions)), today=dt.datetime.strptime(today, "%Y-%m-%d").date(), year_to_x=year_to_x, date_to_x=date_to_x, format_year=format_year, + id_key=self.id_key, ).dump(f) @@ -145,8 +204,14 @@ def main() -> None: args = parser.parse_args() versions = Versions() + assert len(versions.versions) > 10 + Path("include").mkdir(exist_ok=True) + versions.write_csv() - versions.write_svg(args.today) + versions.write_svg(args.today, "_static/release-cycle-all.svg") + + versions = Versions(limit_to_active=True, special_py27=True) + versions.write_svg(args.today, "_static/release-cycle.svg") if __name__ == "__main__": diff --git a/_tools/release_cycle_template.svg.jinja b/_tools/release_cycle_template.svg.jinja index 5d39d307a5..ffc54919e7 100644 --- a/_tools/release_cycle_template.svg.jinja +++ b/_tools/release_cycle_template.svg.jinja @@ -2,29 +2,146 @@ <svg xmlns="http://www.w3.org/2000/svg" class="release-cycle-chart" - viewBox="0 0 {{ diagram_width * SCALE }} {{ diagram_height * SCALE }}" + viewBox="0 0 {{ diagram_width }} {{ diagram_height }}" > + <style> + /* Embedded styles for standalone viewing */ + .release-cycle-chart { + color-scheme: light; - {% for version in versions %} - {% set y = loop.index * LINE_HEIGHT %} + {# Copy vars from Furo theme if present #} + {% for varname, default in { + 'color-foreground-primary': 'light-dark(#333, #fff)', + 'color-background-primary': 'light-dark(#fff, #333)', + 'color-brand-primary': '#4B8BBE', + 'color-background-item': '#e0e0e0', + }.items() %} + --svg-{{varname}}: var(--{{varname}}, {{default}}); + {% endfor %} + + font-family: var( + --font-stack, + -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, + Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji); + width: 100%; + + --blob-border-width: 1.6px; + + --status-bg-color: #CCC; + --status-border-color: #888; + } + .background { + fill: var(--svg-color-background-primary); + } + .release-cycle-year-line { + stroke: var(--svg-color-foreground-primary); + stroke-width: 0.8px; + opacity: 75%; + } + .release-cycle-today-line { + stroke: var(--svg-color-brand-primary); + stroke-width: var(--blob-border-width); + } + .release-cycle-row-shade { + fill: var(--svg-color-background-item); + opacity: 50%; + } + .release-cycle-blob { + stroke-width: var(--blob-border-width); + } + .text-main { + fill: var(--svg-color-foreground-primary); + + /* use specific colours on known backgrounds */ + &.release-cycle-status-security, + &.release-cycle-status-bugfix { + fill: black; + } + } + .text-outline { + /* an outline of the background color, in case it's not set + correctly */ + fill: transparent; + stroke: var(--svg-color-background-primary); + stroke-width: var(--blob-border-width); + + /* use specific colours on known backgrounds */ + &.release-cycle-status-security, + &.release-cycle-status-bugfix { + stroke: var(--status-bg-color); + } + } + .release-cycle-status-end-of-life { + --status-bg-color: #DD2200; + --status-border-color: #FF8888; + } + .release-cycle-status-security { + --status-bg-color: #FFDD44; + --status-border-color: #FF8800; + } + .release-cycle-status-bugfix { + --status-bg-color: #00DD22; + --status-border-color: #008844; + } + .release-cycle-status-prerelease { + --status-bg-color: teal; + --status-border-color: darkgreen; + } + .release-cycle-status-feature { + --status-bg-color: #2222EE; + --status-border-color: #008888; + } + .release-cycle-status-planned { + /* Use grey defaults */ + } + .release-cycle-blob { + fill: var(--status-bg-color); + stroke: transparent; + } + .release-cycle-blob-full { + fill: var(--status-bg-color); + stroke: var(--status-border-color); + } + .release-cycle-border { + fill: transparent; + stroke: var(--status-border-color); + stroke-width: var(--blob-border-width); + } + </style> + <defs> + <linearGradient id="release-cycle-mask-gradient-{{ id_key }}"> + <stop stop-color="black" offset="0%" /> + <stop stop-color="white" offset="100%" /> + </linearGradient> + </defs> + + <rect + class="background" + x="0" + y="0" + width="{{ diagram_width }}" + height="{{ diagram_height }}" + /> - {% if loop.index % 2 %} + {% for version in versions %} + {% set y = version.y * line_height %} + {% if version.y % 2 %} <!-- Row shading --> <rect class="release-cycle-row-shade" x="0em" - y="{{ (y - 1.125) * SCALE }}" - width="{{ diagram_width * SCALE }}" - height="{{ LINE_HEIGHT * SCALE }}" + y="{{ y - 1.125 * SCALE }}" + width="{{ diagram_width }}" + height="{{ line_height }}" /> {% endif %} {% endfor %} {% for year in years %} <text - class="release-cycle-year-text" - x="{{ (year_to_x(year) + year_to_x(year + 1)) / 2 * SCALE }}" - y="{{ (diagram_height - LINE_HEIGHT) * SCALE }}" + class="release-cycle-year-text text-main" + x="{{ (year_to_x(year) + year_to_x(year + 1)) / 2 }}" + y="{{ diagram_height - line_height }}" font-size="{{ SCALE * 0.75 }}" text-anchor="middle" > @@ -33,59 +150,168 @@ {% if not loop.last %} <line class="release-cycle-year-line" - x1="{{ year_to_x(year + 1) * SCALE }}" - x2="{{ year_to_x(year + 1) * SCALE }}" + x1="{{ year_to_x(year + 1) }}" + x2="{{ year_to_x(year + 1) }}" y1="0" - y2="{{ (diagram_height - LINE_HEIGHT) * SCALE }}" + y2="{{ diagram_height - line_height }}" font-size="{{ SCALE }}" /> {% endif %} {% endfor %} - {% for version in versions %} - {% set y = loop.index * LINE_HEIGHT %} + <!-- Gradient mask to fade out end-of-life versions --> + <mask id="release-cycle-mask-{{ id_key }}"> + <rect + x="0" + y="0" + width="{{ legend_width }}" + height="{{ diagram_height }}" + fill="black" + /> + <rect + x="{{ legend_width - right_margin }}" + y="0" + width="{{ right_margin }}" + height="{{ diagram_height }}" + fill="url(#release-cycle-mask-gradient-{{ id_key }})" + /> + <rect + x="{{ legend_width }}" + y="0" + width="{{ diagram_width }}" + height="{{ diagram_height }}" + fill="white" + /> + </mask> - <!-- Legend on the left --> - <text - class="release-cycle-version-label" - x="{{ 0.5 * SCALE }}" - y="{{ y * SCALE }}" - font-size="{{ SCALE }}" - > - Python {{ version.key }} - </text> + {% for version in versions %} + <!-- Colourful blob. --> - <!-- Colourful blob with a label --> + {% set top_y = version.y * line_height - 1 * SCALE %} + {% set height = 1.25 * SCALE %} {% set start_x = date_to_x(version.first_release_date) %} {% set end_x = date_to_x(version.end_of_life_date) %} - {% set mid_x = (start_x + end_x) / 2 %} - <rect - class="release-cycle-blob release-cycle-blob-{{ version.status }}" - x="{{ start_x * SCALE }}" - y="{{ (y - 1) * SCALE }}" - width="{{ (end_x - start_x) * SCALE }}" - height="{{ 1.25 * SCALE }}" - rx="0.25em" - ry="0.25em" - /> - <text - class="release-cycle-blob-label release-cycle-blob-{{ version.status }}" - x="{{ mid_x * SCALE }}" - y="{{ (y - 0.1) * SCALE }}" - font-size="{{ SCALE * 0.75 }}" - text-anchor="middle" - > - {{ version.status }} - </text> + {% set radius = 0.25 * SCALE %} + + <!-- bugfix/security blobs need to be split between the two phases. + Draw the rectangle with two path elements instead. + Thanks Claude.ai for the initial conversion. + --> + {% set middle_x = ([end_x, date_to_x(version.start_security_date)]|min) %} + {% set left_width = (middle_x - start_x) %} + {% set right_width = (end_x - middle_x) %} + + {% if version.status != "end-of-life" %} + <!-- Split the blob using path operations + (Move-to, Vertical/Horizontal, Arc, Z=close shape; + lowercase means relative to the last point.) + We start drawing from the top of the straight boundary + between the half-blobs. + --> + <path + class="release-cycle-blob release-cycle-status-bugfix" + d=" + M{{ middle_x }},{{ top_y }} {#- start -#} + v{{ height }} {#- down -#} + H{{ start_x + radius }} {#- left -#} + a{{ radius }},{{ radius }} 90 0 1 {#- rounded corner -#} + {{ -radius }} {{ -radius }} + v{{ -height + 2*radius }} {#- up -#} + a{{ radius }},{{ radius }} 90 0 1 {#- rounded corner -#} + {{ radius }} {{ -radius }} + Z {#- right -#} + " + /> + <path + class="release-cycle-blob release-cycle-status-security" + d=" + M{{ middle_x }},{{ top_y }} {#- start -#} + v{{ height }} {#- down -#} + H{{ end_x - radius }} {#- right -#} + a{{ radius }},{{ radius }} 90 0 0 {#- rounded corner -#} + {{ radius }} {{ -radius }} + v{{ -height + 2*radius }} {#- up -#} + a{{ radius }},{{ radius }} 90 0 0 {#- rounded corner -#} + {{ -radius }} {{ -radius }} + Z {#- left -#} + " + /> + <!-- Add a common border --> + <rect + class="release-cycle-border release-cycle-status-{{ version.status }}" + x="{{ start_x }}" + y="{{ top_y }}" + width="{{ (end_x - start_x) }}" + height="{{ height }}" + rx="{{ radius }}" + ry="{{ radius }}" + /> + {% else %} + <!-- For EOL releases, use a single rounded rectangle --> + <rect + class="release-cycle-blob release-cycle-blob-full + release-cycle-status-{{ version.status }}" + x="{{ start_x }}" + y="{{ top_y }}" + width="{{ (end_x - start_x) }}" + height="{{ height }}" + rx="{{ radius }}" + ry="{{ radius }}" + mask="url(#release-cycle-mask-{{ id_key }})" + /> + {% endif %} {% endfor %} <!-- A line for today --> <line class="release-cycle-today-line" - x1="{{ date_to_x(today) * SCALE }}" - x2="{{ date_to_x(today) * SCALE }}" + x1="{{ date_to_x(today) }}" + x2="{{ date_to_x(today) }}" y1="0" - y2="{{ (diagram_height - LINE_HEIGHT) * SCALE }}" + y2="{{ diagram_height - line_height }}" font-size="{{ SCALE }}" /> + + {% for version in versions %} + <!-- Label for colourful blob --> + + {% set start_x = date_to_x(version.first_release_date) %} + {% set end_x = date_to_x(version.end_of_life_date) %} + {% set middle_x = ([end_x, date_to_x(version.start_security_date)]|min) %} + {% set small_text_y = version.y * line_height - 0.1 * SCALE %} + + <!-- Add text before/after/inside the blob --> + {% for cls in ('text-outline', 'text-main') %} + <text + class="release-cycle-blob-label {{cls}} release-cycle-status-{{ version.status }}" + font-size="{{ SCALE * 0.75 }}" + y="{{ small_text_y }}" + {% if version.status == "bugfix" %} + x="{{ (start_x + middle_x) / 2 }}" + text-anchor="middle" + {% elif version.status == "security" %} + x="{{ (middle_x + end_x) / 2 }}" + text-anchor="middle" + {% elif version.status == "end-of-life" %} + x="{{ end_x + (0.25 * SCALE) }}" + text-anchor="start" + {% else %} + x="{{ start_x - (0.25 * SCALE) }}" + text-anchor="end" + {% endif %} + > + {{ version.status }} + </text> + {% endfor %} + + <!-- Legend on the left --> + <text + class="release-cycle-version-label text-main" + x="{{ 0.5 * SCALE }}" + y="{{ version.y * line_height }}" + font-size="{{ SCALE }}" + > + Python {{ version.key }} + </text> + {% endfor %} </svg> diff --git a/conf.py b/conf.py index 0319de4ddf..1d88937227 100644 --- a/conf.py +++ b/conf.py @@ -1,4 +1,9 @@ +import json +import os +from urllib.request import urlopen + extensions = [ + 'linklint.ext', 'notfound.extension', 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', @@ -34,6 +39,7 @@ "source_repository": "https://github.com/python/devguide", "source_branch": "main", } +templates_path = ['_templates'] html_static_path = ['_static'] html_css_files = [ 'devguide_overrides.css', @@ -47,6 +53,14 @@ # Set to '' to prevent appending "documentation" to the site title html_title = "" +# Deployment preview information +# (See .readthedocs.yaml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html) +is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external" + +html_context = { + "is_deployment_preview": is_deployment_preview, +} + linkcheck_allowed_redirects = { # Edit page r"https://docs.google.com/document/d/.*/": r"https://docs.google.com/document/d/.*/edit", # noqa: E501 @@ -84,18 +98,10 @@ r'\/.*', ] -# Check the link itself, but ignore anchors that are added by JS -# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_anchors_ignore_for_url -linkcheck_anchors_ignore_for_url = [ - # GitHub - r'https://github.com/.*', -] - linkcheck_ignore = [ - # The voters repo is private and appears as a 404 - 'https://github.com/python/voters', - # The python-core team link is private, redirects to login - 'https://github.com/orgs/python/teams/python-core', + # Checks fail due to rate limits + r'https://github.com/.*', + r'https://www.gnu.org/software/autoconf/', # The Discourse groups are private unless you are logged in 'https://discuss.python.org/groups/staff', 'https://discuss.python.org/groups/moderators', @@ -117,12 +123,21 @@ # Advanced Tools was renamed Development Tools in gh-1149 "advanced-tools/clang.rst": "development-tools/clang.rst", "advanced-tools/gdb.rst": "development-tools/gdb.rst", - # Core Developers - "coredev.rst": "core-developers/become-core-developer.rst", - "committing.rst": "core-developers/committing.rst", - "developers.rst": "core-developers/developer-log.rst", - "experts.rst": "core-developers/experts.rst", - "motivations.rst": "core-developers/motivations.rst", + # Core team + "coredev.rst": "core-team/join-team.rst", + "committing.rst": "core-team/committing.rst", + "developers.rst": "core-team/team-log.rst", + "experts.rst": "core-team/experts.rst", + "motivations.rst": "core-team/motivations.rst", + # core-developers/ -> core-team/ + "core-developers/become-core-developer.rst": "core-team/join-team.rst", + "core-developers/committing.rst": "core-team/committing.rst", + "core-developers/developer-log.rst": "core-team/team-log.rst", + "core-developers/experts.rst": "core-team/experts.rst", + "core-developers/index.rst": "core-team/index.rst", + "core-developers/memorialization.rst": "core-team/memorialization.rst", + "core-developers/motivations.rst": "core-team/motivations.rst", + "core-developers/responsibilities.rst": "core-team/responsibilities.rst", # Developer Workflow "c-api.rst": "developer-workflow/c-api.rst", "communication.rst": "developer-workflow/communication-channels.rst", @@ -135,6 +150,10 @@ # Documentation "docquality.rst": "documentation/help-documenting.rst", "documenting.rst": "documentation/start-documenting.rst", + # Translating + "documentation/translating.rst": "documentation/translations/translating.rst", + "translating.rst": "documentation/translations/translating.rst", + "coordinating.rst": "documentation/translations/coordinating.rst", # Getting Started "fixingissues.rst": "getting-started/fixing-issues.rst", "help.rst": "getting-started/getting-help.rst", @@ -142,10 +161,14 @@ "pullrequest.rst": "getting-started/pull-request-lifecycle.rst", "setup.rst": "getting-started/setup-building.rst", # CPython Internals - "compiler.rst": "internals/compiler.rst", - "exploring.rst": "internals/exploring.rst", - "garbage_collector.rst": "internals/garbage-collector.rst", - "parser.rst": "internals/parser.rst", + "compiler.rst": "internals.rst", + "exploring.rst": "internals.rst", + "garbage_collector.rst": "internals.rst", + "parser.rst": "internals.rst", + "internals/compiler.rst": "internals.rst", + "internals/exploring.rst": "internals.rst", + "internals/garbage_collector.rst": "internals.rst", + "internals/parser.rst": "internals.rst", # Testing and Buildbots "buildbots.rst": "testing/buildbots.rst", "coverage.rst": "testing/coverage.rst", @@ -157,6 +180,56 @@ "tracker.rst": "triage/issue-tracker.rst", "gh-labels.rst": "triage/labels.rst", "triaging.rst": "triage/triaging.rst", + # Contributing guide draft pages + "contrib/code/git.rst": "getting-started/git-boot-camp.rst", + "contrib/code/pull-request-lifecycle.rst": "getting-started/pull-request-lifecycle.rst", + "contrib/code/setup.rst": "getting-started/setup-building.rst", + "contrib/code/testing.rst": "testing/index.rst", + "contrib/code/developer-workflow.rst": "developer-workflow/index.rst", + "contrib/code/index.rst": "index.rst", + "contrib/code/development-tools.rst": "development-tools/index.rst", + "contrib/doc/devguide.rst": "documentation/devguide.rst", + "contrib/doc/help-documenting.rst": "documentation/help-documenting.rst", + "contrib/doc/markup.rst": "documentation/markup.rst", + "contrib/doc/pull-request-lifecycle.rst": "getting-started/pull-request-lifecycle.rst", + "contrib/doc/start-documenting.rst": "documentation/start-documenting.rst", + "contrib/doc/style-guide.rst": "documentation/style-guide.rst", + "contrib/doc/translating.rst": "documentation/translations/index.rst", + "contrib/doc/index.rst": "documentation/index.rst", + "contrib/intro/index.rst": "index.rst", + "contrib/project/channels.rst": "developer-workflow/communication-channels.rst", + "contrib/project/conduct.rst": "index.rst", + "contrib/project/github.rst": "index.rst", + "contrib/project/governance.rst": "index.rst", + "contrib/project/roles.rst": "index.rst", + "contrib/project/generative-ai.rst": "getting-started/generative-ai.rst", + "contrib/project/outreach.rst": "index.rst", + "contrib/project/directory-structure.rst": "getting-started/setup-building.rst", + "contrib/project/index.rst": "index.rst", + "contrib/security.rst": "index.rst", + "contrib/triage/issue-tracker.rst": "triage/issue-tracker.rst", + "contrib/triage/labels.rst": "triage/labels.rst", + "contrib/triage/reviewing.rst": "triage/triaging.rst", + "contrib/triage/triage-team.rst": "triage/triage-team.rst", + "contrib/triage/triaging.rst": "triage/triaging.rst", + "contrib/triage/index.rst": "triage/index.rst", + "contrib/user-success.rst": "index.rst", + "contrib/core-team/committing.rst": "core-team/committing.rst", + "contrib/core-team/experts.rst": "core-team/experts.rst", + "contrib/core-team/index.rst": "core-team/index.rst", + "contrib/core-team/join-team.rst": "core-team/join-team.rst", + "contrib/core-team/motivations.rst": "core-team/motivations.rst", + "contrib/core-team/responsibilities.rst": "core-team/responsibilities.rst", + "contrib/core-team/team-log.rst": "core-team/team-log.rst", + "contrib/workflows/codespaces.rst": "getting-started/setup-building.rst", + "contrib/workflows/compile.rst": "getting-started/setup-building.rst", + "contrib/workflows/get-source.rst": "getting-started/setup-building.rst", + "contrib/workflows/index.rst": "getting-started/setup-building.rst", + "contrib/workflows/install-dependencies.rst": "getting-started/setup-building.rst", + "contrib/workflows/install-git.rst": "getting-started/setup-building.rst", + "contrib/workflows/regenerate.rst": "getting-started/setup-building.rst", + "contrib/workflows/troubleshooting.rst": "getting-started/setup-building.rst", + "contrib/index.rst": "index.rst", } intersphinx_mapping = { @@ -169,23 +242,19 @@ # sphinx-notfound-page notfound_urls_prefix = "/" +# Dynamically expose the Python version associated with the "main" branch. +# Exactly one entry in ``release-cycle.json`` should have ``"branch": "main"``. +with urlopen("https://peps.python.org/api/release-cycle.json") as _f: + _cycle = json.loads(_f.read().decode("utf-8")) + +_main_version = next( + version for version, data in _cycle.items() if data.get("branch") == "main" +) + # prolog and epilogs -rst_prolog = """ -.. |draft| replace:: - This is part of a **Draft** of the Python Contributor's Guide. - Text in square brackets are notes about content to fill in. - Currently, the devguide and this new Contributor's Guide co-exist in the - repo. We are using Sphinx include directives to demonstrate the re-organization. - The final Contributor's Guide will replace the devguide with content in only one - place. - We welcome help with this! - -.. |purpose| replace:: - The :ref:`contrib-plan` page has more details about the current state of this draft - and **how you can help**. See more info about the Contributor Guide in the - discussion forum: `Refactoring the DevGuide`_. - -.. _Refactoring the DevGuide: https://discuss.python.org/t/refactoring-the-devguide-into-a-contribution-guide/63409 +rst_prolog = f""" + +.. |main_version| replace:: {_main_version} """ @@ -207,11 +276,11 @@ ogp_site_url = "https://devguide.python.org/" ogp_site_name = "Python Developer's Guide" ogp_image = "_static/og-image-200x200.png" -ogp_custom_meta_tags = [ +ogp_custom_meta_tags = ( '<meta property="og:image:width" content="200">', '<meta property="og:image:height" content="200">', '<meta name="theme-color" content="#3776ab">', -] +) # Strip the dollar prompt when copying code # https://sphinx-copybutton.readthedocs.io/en/latest/use.html#strip-and-configure-input-prompts-for-code-cells diff --git a/contrib/code/developer-workflow.rst b/contrib/code/developer-workflow.rst deleted file mode 100644 index 416ca2c022..0000000000 --- a/contrib/code/developer-workflow.rst +++ /dev/null @@ -1,25 +0,0 @@ -==================== -Development workflow -==================== - -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`dev-workflow` page from the devguide] - -.. toctree:: - :maxdepth: 5 - - ../../developer-workflow/communication-channels - ../../developer-workflow/development-cycle - ../../developer-workflow/stdlib - ../../developer-workflow/extension-modules - ../../developer-workflow/c-api - ../../developer-workflow/lang-changes - ../../developer-workflow/grammar - ../../developer-workflow/porting - ../../developer-workflow/sbom - ../../developer-workflow/psrt diff --git a/contrib/code/development-tools.rst b/contrib/code/development-tools.rst deleted file mode 100644 index 348ceb95ac..0000000000 --- a/contrib/code/development-tools.rst +++ /dev/null @@ -1,19 +0,0 @@ -================= -Development tools -================= - -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`development-tools` page from the devguide.] - -.. toctree:: - :maxdepth: 5 - - ../../development-tools/clinic - ../../development-tools/gdb - ../../development-tools/clang - ../../development-tools/warnings diff --git a/contrib/code/git.rst b/contrib/code/git.rst deleted file mode 100644 index 7c7aaa57b1..0000000000 --- a/contrib/code/git.rst +++ /dev/null @@ -1,11 +0,0 @@ -======== -Git tips -======== - -.. important:: - - |draft| - - |purpose| - -[More git help for advanced things needed by code contributors.] diff --git a/contrib/code/index.rst b/contrib/code/index.rst deleted file mode 100644 index 7680950663..0000000000 --- a/contrib/code/index.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _c_code: - -================== -Code contributions -================== - -.. important:: - - |draft| - - |purpose| - -[The main page for code contributors.] - -[We'll include code-focused content from the :ref:`main devguide page <devguide-main>`: Quick -reference, Quick links, Proposing changes, and so on.] - -[The existing :ref:`internals` section of the devguide will be fully -migrated into the Python repo.] - - -.. toctree:: - :maxdepth: 5 - - setup - git - pull-request-lifecycle - developer-workflow - testing - development-tools diff --git a/contrib/code/pull-request-lifecycle.rst b/contrib/code/pull-request-lifecycle.rst deleted file mode 100644 index 30c0fd5903..0000000000 --- a/contrib/code/pull-request-lifecycle.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _code-pull-request-lifecycle: - -====================== -Pull request lifecycle -====================== - -.. important:: - - |draft| - - |purpose| - - -[Details of pull requests for code contributions. The existing -:ref:`pull-request-lifecycle` page is long and includes many details. -Some only apply to code contributions, but many are common to all -contributions. Should we keep a common page, with extra steps here, or -should this page have all of the details even if they are duplicated -elsewhere?] - -[See :ref:`docs-pull-request-lifecycle` for the documentation half of this conundrum.] diff --git a/contrib/code/setup.rst b/contrib/code/setup.rst deleted file mode 100644 index 2d14bb0d91..0000000000 --- a/contrib/code/setup.rst +++ /dev/null @@ -1,12 +0,0 @@ -================== -Setup and building -================== - -.. important:: - - |draft| - - |purpose| - -[More setup and build instructions specifically for code contributors, building -on the basics from the :ref:`Getting Started <getting-started>` section.] diff --git a/contrib/code/testing.rst b/contrib/code/testing.rst deleted file mode 100644 index 575d1477a4..0000000000 --- a/contrib/code/testing.rst +++ /dev/null @@ -1,20 +0,0 @@ -===================== -Testing and buildbots -===================== - -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`testing` page from the devguide.] - -.. toctree:: - :maxdepth: 5 - - ../../testing/run-write-tests - ../../testing/silence-warnings - ../../testing/coverage - ../../testing/buildbots - ../../testing/new-buildbot-worker diff --git a/contrib/contrib-plan.rst b/contrib/contrib-plan.rst deleted file mode 100644 index 36a171bf14..0000000000 --- a/contrib/contrib-plan.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _contrib-plan: - -================================== -[Plan for the Contributor's Guide] -================================== - -.. important:: - - |draft| - - |purpose| - -We are in the process of updating and refactoring the devguide to be a -Contributor's Guide. It will highlight the different kinds of contribution -possible, and how to succeed at each kind. - -Currently, the Contibutor's Guide is a draft in this new last section of the -devguide. We welcome feedback, but please understand that some of the current -content is moving or skeletal. - -Repo structure -============== - -While the reorganization is happening, we are keeping the old devguide as it -is. The new Contributor's Guide is represented in this last section, but will -eventually be the only content in the guide. To avoid copying content, we're -using Sphinx include directives to display existing devguide content in its new -Contributor's Guide location. That is not how the eventual Guide will be -built. Once we are ready to make the Contributor's Guide real, we will -rearrange content into its new location. - -How to help -=========== - -To help, you can: - -- `Write an issue`_ detailing a change you'd like to see here. -- `Make a pull request`_ in this repo to add content. -- Join us in the `Python Docs Discord`_ to collaborate with other docs-minded - community members. -- Get in touch with the `Docs Editorial Board`_ to discuss larger documentation - concerns. - -.. _Write an issue: https://github.com/python/devguide/issues -.. _Make a pull request: https://github.com/python/devguide/pulls -.. _Python Docs Discord: https://discord.gg/NeGgyhUZ -.. _Docs Editorial Board: https://python.github.io/editorial-board/ diff --git a/contrib/core-team/committing.rst b/contrib/core-team/committing.rst deleted file mode 100644 index 59cf7c1af2..0000000000 --- a/contrib/core-team/committing.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`committing` page from the devguide. We'll -adjust "core developer" to "core team" where appropriate.] - -.. include:: ../../core-developers/committing.rst diff --git a/contrib/core-team/developer-log.rst b/contrib/core-team/developer-log.rst deleted file mode 100644 index 473cd3c6c6..0000000000 --- a/contrib/core-team/developer-log.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`developer-log` page from the devguide. We'll -adjust "core developer" to "core team" where appropriate.] - -.. include:: ../../core-developers/developer-log.rst diff --git a/contrib/core-team/experts.rst b/contrib/core-team/experts.rst deleted file mode 100644 index 7f2a103cd5..0000000000 --- a/contrib/core-team/experts.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`experts` page from the devguide. We'll -adjust "core developer" to "core team" where appropriate.] - -.. include:: ../../core-developers/experts.rst diff --git a/contrib/core-team/index.rst b/contrib/core-team/index.rst deleted file mode 100644 index 281ed0f479..0000000000 --- a/contrib/core-team/index.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -========= -Core team -========= - -[This is mostly re-organized from the :ref:`core-dev` section of the devguide, -but with "core developer" language changed to "core team" where possible.] - -.. toctree:: - :maxdepth: 5 - - responsibilities - committing - experts - developer-log - motivations - join-team diff --git a/contrib/core-team/join-team.rst b/contrib/core-team/join-team.rst deleted file mode 100644 index 0c893ae08d..0000000000 --- a/contrib/core-team/join-team.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`become-core-developer` page from the devguide with the title changed. We'll -adjust "core developer" to "core team" where appropriate.] - -========================= -How to join the core team -========================= - -.. include:: ../../core-developers/become-core-developer.rst - :start-line: 7 diff --git a/contrib/core-team/motivations.rst b/contrib/core-team/motivations.rst deleted file mode 100644 index c9e0281b6f..0000000000 --- a/contrib/core-team/motivations.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`motivations` page from the devguide. We'll -adjust "core developer" to "core team" where appropriate.] - -.. include:: ../../core-developers/motivations.rst diff --git a/contrib/core-team/responsibilities.rst b/contrib/core-team/responsibilities.rst deleted file mode 100644 index a3de329561..0000000000 --- a/contrib/core-team/responsibilities.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing core developers :ref:`responsibilities` page from the devguide. We'll -adjust "core developer" to "core team" where appropriate.] - -.. include:: ../../core-developers/responsibilities.rst diff --git a/contrib/doc/devguide.rst b/contrib/doc/devguide.rst deleted file mode 100644 index 2c83e52003..0000000000 --- a/contrib/doc/devguide.rst +++ /dev/null @@ -1,12 +0,0 @@ -================================== -Helping with the Developer's Guide -================================== - -.. important:: - - |draft| - - |purpose| - - -[This is the existing :ref:`devguide` page from the devguide.] diff --git a/contrib/doc/help-documenting.rst b/contrib/doc/help-documenting.rst deleted file mode 100644 index befb4b2461..0000000000 --- a/contrib/doc/help-documenting.rst +++ /dev/null @@ -1,12 +0,0 @@ -========================== -Helping with documentation -========================== - -.. important:: - - |draft| - - |purpose| - - -[This is the existing :ref:`help-documenting` page from the devguide.] diff --git a/contrib/doc/index.rst b/contrib/doc/index.rst deleted file mode 100644 index dc8ec93074..0000000000 --- a/contrib/doc/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _c_docs: - -=========================== -Documentation contributions -=========================== - -.. important:: - - |draft| - - |purpose| - - -[The main page for documentation contributors.] - -[We'll include docs-focused content from the :ref:`main devguide page <devguide-main>`: Quick -reference, Quick links, and so on.] - - -.. toctree:: - :maxdepth: 5 - - start-documenting - help-documenting - style-guide - markup - pull-request-lifecycle - translating - devguide diff --git a/contrib/doc/markup.rst b/contrib/doc/markup.rst deleted file mode 100644 index 96b9faad5e..0000000000 --- a/contrib/doc/markup.rst +++ /dev/null @@ -1,12 +0,0 @@ -======================= -reStructuredText markup -======================= - -.. important:: - - |draft| - - |purpose| - - -[This is the existing :ref:`markup` page from the devguide.] diff --git a/contrib/doc/pull-request-lifecycle.rst b/contrib/doc/pull-request-lifecycle.rst deleted file mode 100644 index a62e637283..0000000000 --- a/contrib/doc/pull-request-lifecycle.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _docs-pull-request-lifecycle: - -====================== -Pull request lifecycle -====================== - -.. important:: - - |draft| - - |purpose| - - -[Details of pull requests for documentation contributions. The existing -:ref:`pull-request-lifecycle` page is long and includes many details. -Some only apply to code contributions, but many are common to all -contributions. Should we keep a common page, with documentation tweaks here, or -should this page have only the documentation details even if they are duplicated -elsewhere?] - -[See :ref:`code-pull-request-lifecycle` for the code half of this conundrum.] diff --git a/contrib/doc/start-documenting.rst b/contrib/doc/start-documenting.rst deleted file mode 100644 index c5cf96161b..0000000000 --- a/contrib/doc/start-documenting.rst +++ /dev/null @@ -1,12 +0,0 @@ -=============== -Getting started -=============== - -.. important:: - - |draft| - - |purpose| - - -[This is the existing documentation :ref:`start-documenting` page from the devguide.] diff --git a/contrib/doc/style-guide.rst b/contrib/doc/style-guide.rst deleted file mode 100644 index 87762f3e03..0000000000 --- a/contrib/doc/style-guide.rst +++ /dev/null @@ -1,12 +0,0 @@ -=========== -Style guide -=========== - -.. important:: - - |draft| - - |purpose| - - -[This is the existing documentation :ref:`style-guide` page from the devguide.] diff --git a/contrib/doc/translating.rst b/contrib/doc/translating.rst deleted file mode 100644 index baface2f0d..0000000000 --- a/contrib/doc/translating.rst +++ /dev/null @@ -1,12 +0,0 @@ -=========== -Translating -=========== - -.. important:: - - |draft| - - |purpose| - - -[This is the existing :ref:`translating` page from the devguide.] diff --git a/contrib/get-started/index.rst b/contrib/get-started/index.rst deleted file mode 100644 index 70e61b1b1b..0000000000 --- a/contrib/get-started/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _c_gettingstarted: - -=============== -Getting started -=============== - -.. important:: - - |draft| - - |purpose| - - -* Basic setup -* Git bootcamp (simplified for everyone to use) diff --git a/contrib/index.rst b/contrib/index.rst deleted file mode 100644 index b3ef0d992a..0000000000 --- a/contrib/index.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. _c_root: - -================================== -Python Contributor's Guide (draft) -================================== - -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> - - -.. important:: - - |draft| - - |purpose| - - -[Open question: how to divide content between this Introduction and the -:ref:`introduction <c_intro>`?] - -This guide is a comprehensive resource for :ref:`contributing <contributing>` -to Python_ -- for both new and experienced contributors. It is :ref:`maintained -<devguide>` by the same community that maintains Python. We welcome your -contributions to Python! - -We encourage everyone to contribute to Python. This guide should have -everything you need to get started and be productive. If you still have -questions after reviewing the material in this guide, the `Core Python -Mentorship`_ group is available to help you through the process. - -There are a number of ways to contribute including code, documentation, and -triaging issues. We've organized this guide to provide specifics based on the -type of activity you'll be engaged in. - - -Using this guide -================ - -We recommend reading this guide as needed. You can stop where you feel -comfortable and begin contributing immediately without reading and -understanding everything. If you do choose to skip around this guide, be aware -that it is written assuming preceding sections have been read so you may need -to backtrack to fill in missing concepts and terminology. - -No matter what kind of contribution you'll be making, you should start with -these common sections: - -* :ref:`c_intro` -* :ref:`c_project` -* :ref:`c_gettingstarted` - -Then choose a path based on your type of activity: - -*[The original table on the devguide home had a fourth column for Core -Developers. That made the table wider and more confusing. I don't think core -team members need a quick intro path since they will have been through the -devguide before.]* - -*[I haven't adjusted the links in the table yet other than to add a link to the -major section at the top of each column.]* - -.. list-table:: - :widths: 10 10 10 - :header-rows: 1 - - * - :ref:`Triaging <c_triage>` - - :ref:`Documentation <c_docs>` - - :ref:`Code <c_code>` - * - - * :ref:`tracker` - * :ref:`triaging` - * :ref:`helptriage` - * :ref:`experts` - * :ref:`labels` - * :ref:`gh-faq` - * :ref:`triage-team` - - - * :ref:`docquality` - * :ref:`documenting` - * :ref:`style-guide` - * :ref:`rst-primer` - * :ref:`translating` - * :ref:`devguide` - - - * :ref:`setup` - * :ref:`help` - * :ref:`pullrequest` - * :ref:`runtests` - * :ref:`fixingissues` - * :ref:`communication` - * :ref:`gitbootcamp` - * :ref:`devcycle` - - -.. toctree:: - :maxdepth: 3 - - contrib-plan - intro/index - project/index - get-started/index - triage/index - code/index - doc/index - core-team/index - user-success - security - - -.. _Python: https://www.python.org/ -.. _Core Python Mentorship: https://www.python.org/dev/core-mentorship/ diff --git a/contrib/intro/index.rst b/contrib/intro/index.rst deleted file mode 100644 index c5ba303dfd..0000000000 --- a/contrib/intro/index.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. _c_intro: - -============ -Introduction -============ - -.. important:: - - |draft| - - |purpose| - - - -[Open question: how to divide content between this Introduction and the -:ref:`home page <c_root>`?] - -Welcome! - -New to open source? -=================== - -Python is an open source project, with culture and techniques from the broader -open source world. You might find it helpful to read about open source in -general. A number of individuals from the Python community have contributed to -a series of excellent guides at `Open Source Guides -<https://opensource.guide/>`_. - -Anyone will find the following guides useful: - -* `How to Contribute to Open Source <https://opensource.guide/how-to-contribute/>`_ -* `Building Welcoming Communities <https://opensource.guide/building-community/>`_ - - -Healthy collaboration -===================== - -[Importance of healthy inclusive collaboration] - -[While code is a large part of the project's success, project management, documentation, governance, sprint outreach, etc. matter.] - -[We respect the individual skills people bring to the project and strive to create and maintain a culture of inclusion.] - -About this guide -================ - -Types of contribution -===================== - -[Pathways for contributors] - -Helping with this guide -======================= diff --git a/contrib/project/channels.rst b/contrib/project/channels.rst deleted file mode 100644 index 711dbe5879..0000000000 --- a/contrib/project/channels.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -====================== -Communication channels -====================== - -* Repos -* Discourse -* Discord -* Mailing lists (deprioritize) -* Where to get help diff --git a/contrib/project/conduct.rst b/contrib/project/conduct.rst deleted file mode 100644 index 37fe3bbfa7..0000000000 --- a/contrib/project/conduct.rst +++ /dev/null @@ -1,16 +0,0 @@ -=============== -Code of Conduct -=============== - -.. important:: - - |draft| - - |purpose| - - -[Brief summary of the code of conduct, with links to official source.] - -* Standard for communication -* How to report -* Enforcement details diff --git a/contrib/project/generative-ai.rst b/contrib/project/generative-ai.rst deleted file mode 100644 index 6cb5b62ffc..0000000000 --- a/contrib/project/generative-ai.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -[This is the existing :ref:`generative-ai` page from the devguide.] - -.. include:: ../../getting-started/generative-ai.rst diff --git a/contrib/project/github.rst b/contrib/project/github.rst deleted file mode 100644 index fe45c6b8b1..0000000000 --- a/contrib/project/github.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. important:: - - |draft| - - |purpose| - -====== -GitHub -====== - -[Where are the actual artifacts?] - -* Main CPython repos -* Core workflow repos -* Infrastructure repos diff --git a/contrib/project/governance.rst b/contrib/project/governance.rst deleted file mode 100644 index a4bc66ff1b..0000000000 --- a/contrib/project/governance.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -========== -Governance -========== - -[How decisions are made, who is involved, how to participate.] - -Steering Council -================ - -Documentation Editorial Board -============================= - -Typing Council -============== - - -Others? -======= diff --git a/contrib/project/index.rst b/contrib/project/index.rst deleted file mode 100644 index 5d26b15aab..0000000000 --- a/contrib/project/index.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _c_project: - -=================== -The CPython project -=================== - -.. important:: - - |draft| - - |purpose| - - -[Give the reader an understanding of the project as a whole. What are the -moving parts, who is involved, how do they interact?] - -* Structure - -.. toctree:: - :maxdepth: 5 - - conduct - roles - governance - generative-ai.rst - github - channels - outreach diff --git a/contrib/project/outreach.rst b/contrib/project/outreach.rst deleted file mode 100644 index d43aa8e9de..0000000000 --- a/contrib/project/outreach.rst +++ /dev/null @@ -1,12 +0,0 @@ -======== -Outreach -======== - -.. important:: - - |draft| - - |purpose| - - -* Sprints diff --git a/contrib/project/roles.rst b/contrib/project/roles.rst deleted file mode 100644 index 8336fe4651..0000000000 --- a/contrib/project/roles.rst +++ /dev/null @@ -1,17 +0,0 @@ -===== -Roles -===== - -.. important:: - - |draft| - - |purpose| - - -[Quick overview of the roles people play. Core team has its own section.] - -* Core team -* Triager -* Contributors - * types of contributions diff --git a/contrib/security.rst b/contrib/security.rst deleted file mode 100644 index db40b4a167..0000000000 --- a/contrib/security.rst +++ /dev/null @@ -1,13 +0,0 @@ -========================================= -Security and infrastructure contributions -========================================= - -.. important:: - - |draft| - - |purpose| - -* Security -* Infrastructure -* Core workflow diff --git a/contrib/triage/index.rst b/contrib/triage/index.rst deleted file mode 100644 index 0a547d9d77..0000000000 --- a/contrib/triage/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _c_triage: - -=================== -Issues and triaging -=================== - -.. toctree:: - :maxdepth: 5 - - issue-tracker - triaging - labels - reviewing - triage-team diff --git a/contrib/triage/issue-tracker.rst b/contrib/triage/issue-tracker.rst deleted file mode 100644 index a5777bc81d..0000000000 --- a/contrib/triage/issue-tracker.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`issue-tracker` page from the devguide] - -.. include:: ../../triage/issue-tracker.rst diff --git a/contrib/triage/labels.rst b/contrib/triage/labels.rst deleted file mode 100644 index c364817333..0000000000 --- a/contrib/triage/labels.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`labels` page from the devguide] - -.. include:: ../../triage/labels.rst diff --git a/contrib/triage/reviewing.rst b/contrib/triage/reviewing.rst deleted file mode 100644 index 060f6b78dd..0000000000 --- a/contrib/triage/reviewing.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. important:: - - |draft| - - |purpose| - - -========= -Reviewing -========= - -* How? Etiquette? -* How to request a review? diff --git a/contrib/triage/triage-team.rst b/contrib/triage/triage-team.rst deleted file mode 100644 index a9b59056a9..0000000000 --- a/contrib/triage/triage-team.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`triage-team` page from the devguide] - -.. include:: ../../triage/triage-team.rst diff --git a/contrib/triage/triaging.rst b/contrib/triage/triaging.rst deleted file mode 100644 index 22e1ccc657..0000000000 --- a/contrib/triage/triaging.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. important:: - - |draft| - - |purpose| - -[This is the existing :ref:`triaging` page from the devguide] - -.. include:: ../../triage/triaging.rst diff --git a/contrib/user-success.rst b/contrib/user-success.rst deleted file mode 100644 index 2a9ef5d4e5..0000000000 --- a/contrib/user-success.rst +++ /dev/null @@ -1,14 +0,0 @@ -======================================= -Accessibility, design, and user success -======================================= - -.. important:: - - |draft| - - |purpose| - - -* Accessibility -* Design -* User success diff --git a/core-developers/committing.rst b/core-team/committing.rst similarity index 59% rename from core-developers/committing.rst rename to core-team/committing.rst index 326578c0b3..c606df3839 100644 --- a/core-developers/committing.rst +++ b/core-team/committing.rst @@ -5,7 +5,7 @@ Accepting pull requests .. highlight:: none -This page is a step-by-step guide for core developers who need to assess, +This page is a step-by-step guide for the core team to assess, merge, and possibly backport a pull request on the main repository. Assessing a pull request @@ -54,15 +54,16 @@ to enter the public source tree. Ask yourself the following questions: developer can apply the label ``needs backport to X.Y`` to the pull request. Once the backport pull request has been created, remove the ``needs backport to X.Y`` label from the original pull request. (Only - core developers and members of the :ref:`Python Triage Team <triage-team>` + the core team and members of the :ref:`Python Triage Team <triage-team>` can apply labels to GitHub pull requests). * **Does the pull request pass a check indicating that the submitter has signed the CLA?** Make sure that the contributor has signed a `Contributor - Licensing Agreement <https://www.python.org/psf/contrib/contrib-form/>`_ + Licensing Agreement <https://www.python.org/psf/contrib/contrib-form/>`__ (CLA), unless their change has no possible intellectual property associated with it (for example, fixing a spelling mistake in documentation). - The `CPython CLA Bot <https://github.com/apps/cpython-cla-bot/>`_ + The `Python Software Foundation Contributor License Agreement Management Bot + <https://github.com/psf/clabot>`__ checks whether the author has signed the CLA, and replies in the PR if they haven't. For further questions about the CLA process, write to contributors@python.org. @@ -72,104 +73,10 @@ to enter the public source tree. Ask yourself the following questions: significant improvements, or backwards-incompatible changes), then an entry in the ``What's New in Python`` document (in ``Doc/whatsnew/``) should be added as well. Changes that affect only documentation generally do not - require a ``NEWS`` entry. (See the following section for more information.) + require a ``NEWS`` entry. -.. _news-entry: -.. _what-s-new-and-news-entries: - -Updating NEWS and What's New in Python --------------------------------------- - -Changes that require NEWS entries -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Most changes made to the codebase deserve an entry in :cpy-file:`Misc/NEWS.d`, -except for the following: - -* documentation changes -* test changes -* strictly internal changes with no user-visible effects -* changes that already have a ``NEWS`` entry -* reverts that have not yet been included in any formal release - (including alpha and beta releases) - -For the last two, note the following: - -#. **If a change is reverted prior to release**, then the corresponding - entry is simply removed. Otherwise, a new entry must be added noting - that the change has been reverted (for example, when a feature is released in - an alpha and then cut prior to the first beta). - -#. **If a change is a fix (or other adjustment) to an earlier unreleased - change and the original** ``NEWS`` **entry remains valid**, then no additional - entry is needed. - -Changes that require "What's New in Python" entries -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If a change is particularly interesting for end users (for example, new features, -significant improvements, or backwards-incompatible changes), add an entry in -the "What's New in Python" document (in :cpy-file:`Doc/whatsnew/`) -in addition to the ``NEWS`` entry. - -In most cases, it is sufficient to reuse the wording from the ``NEWS`` entry -in the "What's New in Python" entry. - -.. note:: - - A change that needs an entry in "What's New in Python", - is very likely not suitable for inclusion in a maintenance release. - -How to add a NEWS entry -^^^^^^^^^^^^^^^^^^^^^^^ - -``NEWS`` entries go into the ``Misc/NEWS.d`` directory as individual files. The -``NEWS`` entry can be created by using `blurb-it <https://blurb-it.herokuapp.com/>`_, -or the :pypi:`blurb` tool and its ``blurb add`` command. - -If you are unable to use the tool, then you can create the ``NEWS`` entry file -manually. The ``Misc/NEWS.d`` directory contains a sub-directory named -``next``, which contains various sub-directories representing classifications -for what was affected (for example, ``Misc/NEWS.d/next/Library`` for changes relating -to the standard library). The file name itself should be in the format -``<datetime>.gh-issue-<issue-number>.<nonce>.rst``: - -* ``<datetime>`` is today's date joined with a hyphen (``-``) to your current - local time, in the ``YYYY-MM-DD-hh-mm-ss`` format (for example, ``2017-05-27-16-46-23``). -* ``<issue-number>`` is the issue number the change is for (for example, ``12345`` - for ``gh-issue-12345``). -* ``<nonce>`` is a unique string to guarantee that the file name is - unique across branches (for example, ``Yl4gI2``). It is typically six characters - long, but it can be any length of letters and numbers. Its uniqueness - can be satisfied by typing random characters on your keyboard. - -As a result, a file name can look something like -``Misc/NEWS.d/next/Library/2017-05-27-16-46-23.gh-issue-12345.Yl4gI2.rst``. - -How to write a NEWS entry -^^^^^^^^^^^^^^^^^^^^^^^^^ - -All ``NEWS`` entries end up being part of the changelog. -The changelog contains *a lot* of entries, -and its intended audience is mainly users, not core devs and contributors. -Take this into consideration when wording your ``NEWS`` entry. -Describe the user-visible effects of your change succinctly and accurately; -avoid long technical elaborations, digressions, and do not expect or require -the reader to have read the actual diff for the change. - -The contents of a ``NEWS`` file should be valid reStructuredText. An 80 character -column width should be used. There is no indentation or leading marker in the -file (for example, ``-``). There is also no need to start the entry with the issue -number since it is part of the file name. You can use -:ref:`inline markups <rest-inline-markup>` too. Here is an example of a ``NEWS`` -entry:: - - Fix warning message when :func:`os.chdir` fails inside - :func:`test.support.temp_cwd`. Contributed by Chris Jerdonek. - -The inline Sphinx roles like ``:func:`` can be used help readers -find more information. You can build HTML and verify that the -link target is appropriate by using :ref:`make html <building-using-make>`. + .. seealso:: + :ref:`what-s-new-and-news-entries` Working with Git_ @@ -178,7 +85,7 @@ Working with Git_ .. seealso:: :ref:`gitbootcamp` -As a core developer, you have the ability to push changes to the official +As a core team member, you have the ability to push changes to the official Python repositories, so you need to be careful with your workflow: * **You should not push new branches to the main repository.** You can @@ -223,12 +130,12 @@ Backporting changes to an older version ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If it is determined that a pull request needs to be backported into one or -more of the maintenance branches, then a core developer can apply the label +more of the maintenance branches, then a core team member can apply the label ``needs backport to X.Y`` to the pull request. After the pull request has been merged, miss-islington (bot) will first try to do the backport automatically. If miss-islington is unable to do it, -then the pull request author or the core developer who merged it should look into +then the pull request author or the core team member who merged it should look into backporting it themselves, using the backport generated by cherry_picker.py_ as a starting point. @@ -251,7 +158,7 @@ Note that cherry_picker.py_ adds the branch prefix automatically. Once the backport pull request has been created, remove the ``needs backport to X.Y`` label from the original pull request. (Only -core developers and members of the :ref:`Python Triage Team <triage-team>` +members of the core team and :ref:`Python Triage Team <triage-team>` can apply labels to GitHub pull requests). .. _cherry_picker.py: https://github.com/python/cherry-picker diff --git a/core-developers/developers.csv b/core-team/core-team.csv similarity index 88% rename from core-developers/developers.csv rename to core-team/core-team.csv index a138f37397..48234eff4d 100644 --- a/core-developers/developers.csv +++ b/core-team/core-team.csv @@ -1,5 +1,10 @@ +Itamar Oren,itamaro,2026-02-16,, +Emma Smith,emmatyping,2025-07-31,, +Tomas Roun,tomasr8,2025-06-16,, +Peter Bierma,ZeroIntensity,2025-06-16,, +Diego Russo,diegorusso,2025-05-13,, Bénédikt Tran,picnixz,2025-01-10,, -Savannah Ostrowski,savannahostrowski,2024-11-13,, +Savannah Ostrowski,savannahostrowski,2024-11-13,, Matt Page,mpage,2024-10-10,, Kirill Podoprigora,Eclips4,2024-09-20,, Ned Batchelder,nedbat,2024-07-16,, @@ -31,7 +36,7 @@ Kyle Stanley,aeros,2020-04-14,, Donghee Na,corona10,2020-04-08,, Karthikeyan Singaravelan,tirkarthi,2019-12-31,, Joannah Nanjekye,nanjekyejoannah,2019-09-23,, -Abhilash Raj,maxking,2019-08-06,, +Abhilash Raj,maxking,2019-08-06,2022-11-30,Privileges relinquished on 2022-11-30 Paul Ganssle,pganssle,2019-06-15,, Stéphane Wirtel,matrixise,2019-04-08,, Stefan Behnel,scoder,2019-04-08,, @@ -52,7 +57,7 @@ Xavier de Gaye,xdegaye,2016-06-03,2018-01-25,Privileges relinquished on 2018-01- Davin Potts,applio,2016-03-06,, Martin Panter,vadmium,2015-08-10,2020-11-26, Paul Moore,pfmoore,2015-03-15,, -Robert Collins,rbtcollins,2014-10-16,,To work on unittest +Robert Collins,rbtcollins,2014-10-16,2021-11-30,To work on unittest; privileges relinquished on 2021-11-30 Berker Peksağ,berkerpeksag,2014-06-26,, Steve Dower,zooba,2014-05-10,, Kushal Das,kushaldas,2014-04-14,, @@ -69,16 +74,16 @@ Hynek Schlawack,hynek,2012-05-14,, Richard Oudkerk,,2012-04-29,2017-02-10,For multiprocessing module; did not make GitHub transition Andrew Svetlov,asvetlov,2012-03-13,,At PyCon sprint Petri Lehtinen,akheron,2011-10-22,2020-11-12, -Meador Inge,meadori,2011-09-19,2020-11-26, +Meador Inge,meadori,2011-09-19,, Jeremy Kloth,jkloth,2011-09-12,, Sandro Tosi,sandrotosi,2011-08-01,, Alex Gaynor,alex,2011-07-18,,For PyPy compatibility (since expanded scope) Charles-François Natali,,2011-05-19,2017-02-10,Did not make GitHub transition Nadeem Vawda,,2011-04-10,2017-02-10,Did not make GitHub transition -Carl Friedrich Bolz-Tereick,cfbolz,2011-03-21,,for stdlib compatibility work for PyPy +CF Bolz-Tereick,cfbolz,2011-03-21,,for stdlib compatibility work for PyPy Jason R. Coombs,jaraco,2011-03-14,,For sprinting on distutils2 Ross Lagerwall,,2011-03-13,2017-02-10,Did not make GitHub transition -Eli Bendersky,eliben,2011-01-11,2020-11-26, +Eli Bendersky,eliben,2011-01-11,2020-11-26,Relinquished privileges on 2020-11-26 Ned Deily,ned-deily,2011-01-09,, David Malcolm,davidmalcolm,2010-10-27,2020-11-12,relinquished privileges on 2020-11-12 Tal Einat,taleinat,2010-10-04,,Initially for IDLE @@ -100,12 +105,12 @@ Doug Hellmann,dhellmann,2009-09-20,2020-11-11,For documentation; relinquished pr Frank Wierzbicki,,2009-08-02,2017-02-10,For Jython compatibility; did not make GitHub transition Ezio Melotti,ezio-melotti,2009-06-07,,For documentation Philip Jenvey,pjenvey,2009-05-07,2020-11-26,For Jython compatibility -Michael Foord,voidspace,2009-04-01,,For IronPython compatibility +Michael Foord,voidspace,2009-04-01,2025-01-24,For IronPython compatibility; deceased R\. David Murray,bitdancer,2009-03-30,, Chris Withers,cjw296,2009-03-08,, Tarek Ziadé,tarekziade,2008-12-21,2017-02-10,For distutils module Hirokazu Yamamoto,,2008-08-12,2017-02-10,For Windows build; did not make GitHub transition -Armin Ronacher,mitsuhiko,2008-07-23,2020-11-26,For documentation toolset and ast module +Armin Ronacher,mitsuhiko,2008-07-23,,For documentation toolset and ast module Antoine Pitrou,pitrou,2008-07-16,, Senthil Kumaran,orsenthil,2008-06-16,, Jesse Noller,,2008-06-16,2017-02-10,For multiprocessing module; did not make GitHub transition @@ -114,9 +119,9 @@ Guilherme Polo,,2008-04-24,2017-02-10,Did not make GitHub transition Jeroen Ruigrok van der Werven,,2008-04-12,2017-02-10,For documentation; did not make GitHub transition Benjamin Peterson,benjaminp,2008-03-25,,For bug triage David Wolever,wolever,2008-03-17,2020-11-21,For 2to3 module -Trent Nelson,tpn,2008-03-17,2020-11-26, +Trent Nelson,tpn,2008-03-17,, Mark Dickinson,mdickinson,2008-01-06,2024-08-13,For maths-related work -Amaury Forgeot d'Arc,amauryfa,2007-11-09,2020-11-26, +Amaury Forgeot d'Arc,amauryfa,2007-11-09,2020-11-26,Relinquished privileges on 2020-11-26 Christian Heimes,tiran,2007-10-31,, Bill Janssen,,2007-08-28,2017-02-10,For ssl module; did not make GitHub transition Jeffrey Yasskin,,2007-08-09,2017-02-10,Did not make GitHub transition @@ -142,9 +147,9 @@ Facundo Batista,facundobatista,2004-10-16,, Sean Reifschneider,,2004-09-17,2017-02-10,Did not make GitHub transition Johannes Gijsbers,,2004-08-14,2005-07-27,Privileges relinquished on 2005-07-27 Matthias Klose,doko42,2004-08-04,, -PJ Eby,pjeby,2004-03-24,2020-11-26, +PJ Eby,pjeby,2004-03-24,2020-11-26,Relinquished privileges on 2020-11-26 Vinay Sajip,vsajip,2004-02-20,, -Hye-Shik Chang,hyeshik,2003-12-10,, +Hye-Shik Chang,hyeshik,2003-12-10,2025-02-28,Privileges relinquished on 2025-02-28 Armin Rigo,,2003-10-24,2012-06-01,Privileges relinquished in 2012 Andrew McNamara,,2003-06-09,2017-02-10,Did not make GitHub transition Samuele Pedroni,,2003-05-16,2017-02-10,Did not make GitHub transition @@ -153,11 +158,11 @@ Brett Cannon,brettcannon,2003-04-18,, David Goodger,,2003-01-02,2017-02-10,Did not make GitHub transition Gustavo Niemeyer,,2002-11-05,2017-02-10,Did not make GitHub transition Tony Lownds,,2002-09-22,2017-02-10,Did not make GitHub transition -Steve Holden,holdenweb,2002-06-14,2017-02-10,"Relinquished privileges on 2005-04-07, +Steve Holden,holdenweb,2002-06-14,2017-02-10,"Relinquished privileges on 2005-04-07, but granted again for Need for Speed sprint; did not make GitHub transition" Christian Tismer,ctismer,2002-05-17,,For Need for Speed sprint Jason Tishler,,2002-05-15,2017-02-10,Did not make GitHub transition -Walter Dörwald,doerwalter,2002-03-21,, +Walter Dörwald,doerwalter,2002-03-21,2021-11-16,Relinquished privileges on 2021-11-16 Andrew MacIntyre,,2002-02-17,2016-01-02,Privileges relinquished 2016-01-02 Gregory P. Smith,gpshead,2002-01-08,, Anthony Baxter,,2001-12-21,2017-02-10,Did not make GitHub transition @@ -190,7 +195,7 @@ Eric S. Raymond,,2000-06-02,2017-02-10,Did not make GitHub transition Greg Stein,,1999-11-07,2017-02-10,Did not make GitHub transition Just van Rossum,,1999-01-22,2017-02-10,Did not make GitHub transition Greg Ward,,1998-12-18,2017-02-10,Did not make GitHub transition -Andrew Kuchling,akuchling,1998-04-09,, +Andrew Kuchling,akuchling,1998-04-09,2022-11-09,Privileges relinquished 2022-11-09 Ken Manheimer,,1998-03-03,2005-04-08,Privileges relinquished on 2005-04-08 Jeremy Hylton,jeremyhylton,1997-08-13,, Roger E. Masse,,1996-12-09,2017-02-10,Did not make GitHub transition diff --git a/core-developers/experts.rst b/core-team/experts.rst similarity index 51% rename from core-developers/experts.rst rename to core-team/experts.rst index ec9fc23067..87d3ba4c73 100644 --- a/core-developers/experts.rst +++ b/core-team/experts.rst @@ -20,12 +20,9 @@ following is added to an issue or pull request, they will be notified automatically. The :cpy-file:`.github/CODEOWNERS` file is also used to indicate maintainers that will be automatically added as reviewers to pull requests. +Names followed by a '*' may be assigned issues involving the module or topic. Unless a name is followed by a '*', you should never assign an issue to -that person. Names followed by a '*' may be assigned issues involving the -module or topic. - -Names followed by a '^' indicate old bugs.python.org usernames, for people -that did not transition to GitHub. +that person. The Platform and Interest Area tables list broader fields in which various people have expertise. These people can also be contacted for help, @@ -52,212 +49,116 @@ Stdlib ==================== ============================================= Module Maintainers ==================== ============================================= -__future__ __main__ gvanrossum, ncoghlan -_thread -abc -argparse savannahostrowski* -array +annotationlib JelleZijlstra* +argparse savannahostrowski*, serhiy-storchaka* ast benjaminp, pablogsal, isidentical, JelleZijlstra, eclips4 asyncio 1st1, asvetlov, gvanrossum, graingert, kumaraditya303, willingc -atexit -base64 -bdb -binascii bisect rhettinger* -builtins -bz2 -calendar -cmath -cmd -code -codecs malemburg, doerwalter -codeop +codecs malemburg collections rhettinger* -collections.abc rhettinger*, stutzbach^ -colorsys +collections.abc rhettinger* compileall carljm -concurrent.futures pitrou, brianquinlan, gpshead* +compression.zlib Yhg1s, gpshead*, emmatyping +compression.zstd emmatyping* +concurrent.futures pitrou, gpshead* configparser ambv* contextlib ncoghlan, 1st1 -contextvars -copy avassalotti -copyreg avassalotti -cProfile -csv smontanaro (inactive) -ctypes theller (inactive), abalkin, amauryfa, meadori +copy serhiy-storchaka* +copyreg serhiy-storchaka* +csv serhiy-storchaka* curses Yhg1s dataclasses ericvsmith*, carljm -datetime abalkin, pganssle -dbm +datetime pganssle decimal facundobatista, rhettinger -difflib tim-one (inactive) dis 1st1 -doctest tim-one (inactive) -email warsaw, bitdancer*, maxking +email warsaw, bitdancer* encodings malemburg ensurepip ncoghlan, dstufft, pradyunsg, pfmoore -enum eliben*, warsaw, ethanfurman* +enum warsaw, ethanfurman* errno Yhg1s -faulthandler vstinner, gpshead +faulthandler vstinner, gpshead, ZeroIntensity* fcntl Yhg1s -filecmp -fileinput -fnmatch -fractions +fnmatch serhiy-storchaka* ftplib giampaolo* functools rhettinger* -gc pitrou, pablogsal -getopt -getpath FFY00 -getpass -gettext -glob -grp -gzip +gc pitrou, pablogsal, nascheme +getopt serhiy-storchaka* +getpath FFY00* +gettext tomasr8 +glob serhiy-storchaka* hashlib tiran, gpshead*, picnixz -heapq rhettinger*, stutzbach^ +heapq rhettinger* hmac tiran, gpshead*, picnixz html ezio-melotti* -http -idlelib kbkaiser (inactive), terryjreedy*, serwy (inactive), - taleinat -imaplib -imghdr -importlib brettcannon +idlelib terryjreedy*, taleinat +importlib brettcannon, FFY00* inspect 1st1 -io benjaminp, stutzbach^ -ipaddress pmoody^ +io benjaminp itertools rhettinger* -json etrepum (inactive), ezio-melotti, rhettinger -keyword -libmpdec -linecache +json ezio-melotti, rhettinger, serhiy-storchaka* locale malemburg logging vsajip -lzma -mailbox -marshal -math rhettinger, stutzbach^ -mimetypes +math rhettinger mmap Yhg1s -modulefinder theller (inactive), jvr^ -msilib -msvcrt -multiprocessing applio*, pitrou, jnoller^ (inactive), sbt^ (inactive), gpshead* -netrc -nis -nntplib -numbers -operator -optparse mitsuhiko -os -os.path serhiy-storchaka -ossaudiodev +modulefinder FFY00 +multiprocessing pitrou, gpshead* +optparse serhiy-storchaka* +os.path serhiy-storchaka* parser pablogsal pathlib barneygale* pdb gaogaotiantian -pickle avassalotti -pickletools avassalotti -pipes -pkgutil +pickle serhiy-storchaka* +pickletools serhiy-storchaka* +pkgutil FFY00* platform malemburg -plistlib -poplib posix larryhastings, gpshead -pprint freddrake -profile -pstats pty Yhg1s* -pwd py_compile carljm pyclbr isidentical -pydoc AA-Turner +pydoc AA-Turner, serhiy-storchaka* queue rhettinger* -quopri random rhettinger -re ezio-melotti, serhiy-storchaka +re ezio-melotti, serhiy-storchaka* readline Yhg1s -reprlib resource Yhg1s -rlcompleter -runpy ncoghlan -sched -secrets -select -selectors neologix^, giampaolo -shelve -shlex -shutil tarekziade, giampaolo +runpy ncoghlan, FFY00 +selectors giampaolo +shutil giampaolo signal gpshead -site -smtplib -sndhdr +site FFY00* socket gpshead -socketserver -spwd -sqlite3 ghaering^, erlend-aasland* -ssl jackjansen, tiran, dstufft, alex +sqlite3 erlend-aasland* +ssl tiran, dstufft, alex stat tiran -statistics stevendaprano, rhettinger -string -stringprep -struct meadori -subprocess astrand^ (inactive), giampaolo, gpshead* +statistics rhettinger +subprocess giampaolo, gpshead* symtable benjaminp -sys -sysconfig FFY00 -syslog jafo^* -tabnanny tim-one (inactive) -tarfile gustaebel -tempfile +sysconfig FFY00* +tempfile serhiy-storchaka* termios Yhg1s -test ezio-melotti -textwrap +test ezio-melotti, serhiy-storchaka* threading pitrou, gpshead -time abalkin, pganssle -timeit -tkinter gpolo^, serhiy-storchaka -token -tokenize meadori +time pganssle +tkinter serhiy-storchaka* tomllib hauntsaninja* -trace abalkin traceback iritkatriel tracemalloc vstinner tty Yhg1s* -turtle gregorlingl^, willingc +turtle willingc turtledemo terryjreedy* types 1st1 typing gvanrossum, JelleZijlstra*, AlexWaygood*, carljm, sobolevn* unicodedata malemburg, ezio-melotti -unittest voidspace*, ezio-melotti, rbtcollins, gpshead -unittest.mock voidspace* +unittest ezio-melotti, gpshead, serhiy-storchaka* urllib orsenthil -uu -uuid -venv vsajip, FFY00 -warnings -wave -weakref freddrake -webbrowser -winreg stutzbach^ -winsound -wsgiref pjenvey -xdrlib -xml.dom -xml.dom.minidom -xml.dom.pulldom -xml.etree eliben*, scoder -xml.parsers.expat -xml.sax -xml.sax.handler -xml.sax.saxutils -xml.sax.xmlreader -xmlrpc +venv vsajip, FFY00* +weakref nascheme +xml.etree scoder zipapp pfmoore -zipfile alanmcintyre^, serhiy-storchaka, Yhg1s, gpshead +zipfile serhiy-storchaka, Yhg1s, gpshead zipimport Yhg1s* -zlib Yhg1s, gpshead* +zoneinfo pganssle ==================== ============================================= @@ -267,7 +168,8 @@ Tools ================== =========== Tool Maintainers ================== =========== -Argument Clinic larryhastings, AlexWaygood*, erlend-aasland +Argument Clinic larryhastings, AlexWaygood*, erlend-aasland, + serhiy-storchaka* Deepfreeze gvanrossum, kumaraditya303 PEG Generator gvanrossum, pablogsal, lysnikolaou ================== =========== @@ -287,20 +189,15 @@ for “their” platform as a third-party project. =================== =========== Platform Maintainers =================== =========== -AIX edelsohn, ayappanec +AIX ayappanec Android mhsmith -Cygwin jlt63^, stutzbach^ Emscripten hoodmane, pmp-p, rdb, rth, ryanking13 -FreeBSD -HP-UX iOS freakboy3742, ned-deily Linux macOS ronaldoussoren, ned-deily, freakboy3742 NetBSD1 -OS2/EMX aimacintyre^ -Solaris/OpenIndiana jcea -Windows tjguk, zware, zooba, pfmoore -JVM/Java frank.wierzbicki^ +Solaris/OpenIndiana jcea, kulikjak +Windows tjguk, zooba, pfmoore =================== =========== @@ -308,13 +205,13 @@ Miscellaneous ============= ================== ========================================================== -Interest Area Maintainers +Interest area Maintainers ================== ========================================================== -algorithms rhettinger* -argument clinic larryhastings, AlexWaygood*, erlend-aasland -ast/compiler benjaminp, 1st1, pablogsal, markshannon, isidentical, brandtbucher, carljm, iritkatriel -autoconf/makefiles Yhg1s* -bsd +algorithms rhettinger*, serhiy-storchaka +argument clinic larryhastings, AlexWaygood*, erlend-aasland, + serhiy-storchaka* +AST/compiler benjaminp, 1st1, pablogsal, markshannon, isidentical, brandtbucher, carljm, iritkatriel +autoconf/makefiles Yhg1s*, emmatyping issue tracker ezio-melotti buildbots zware, pablogsal bytecode benjaminp, 1st1, markshannon, brandtbucher, carljm, iritkatriel @@ -328,46 +225,251 @@ devguide merwok, ezio-melotti, willingc, Mariatta, hugovk, documentation ezio-melotti, merwok, JulienPalard, willingc, hugovk, AA-Turner, AlexWaygood* emoji Mariatta -extension modules encukou, ncoghlan -filesystem giampaolo -frozen modules ericsnowcurrently, gvanrossum, kumaraditya303 +extension modules encukou, ncoghlan, FFY00 +filesystem +frozen modules ericsnowcurrently, gvanrossum, kumaraditya303, FFY00 f-strings ericvsmith* GUI -i18n malemburg, merwok -import machinery brettcannon, ncoghlan, ericsnowcurrently, FFY00 -initialization FFY00 -io benjaminp, stutzbach^, gpshead +i18n malemburg, merwok, tomasr8 +import machinery brettcannon, ncoghlan, ericsnowcurrently, FFY00* +initialization FFY00* +io benjaminp, gpshead JIT brandtbucher*, savannahostrowski* locale malemburg -mathematics malemburg, stutzbach^, rhettinger -memory management tim-one, malemburg, Yhg1s +mathematics malemburg, rhettinger, serhiy-storchaka +memory management tim-one, malemburg, Yhg1s, nascheme memoryview -networking giampaolo, gpshead +networking gpshead object model benjaminp, Yhg1s -packaging tarekziade, malemburg, alexis^, merwok, dstufft, pfmoore +packaging malemburg, merwok, dstufft, pfmoore, emmatyping, FFY00 pattern matching brandtbucher* -peg parser gvanrossum, pablogsal, lysnikolaou -performance vstinner, serhiy-storchaka, 1st1, rhettinger, markshannon, brandtbucher, carljm, Fidget-Spinner, - AlexWaygood* -pip ncoghlan, dstufft, pfmoore, Marcus.Smith^, pradyunsg -py3 transition benjaminp -release management tarekziade, malemburg, benjaminp, warsaw, - gvanrossum, anthonybaxter^, merwok, ned-deily, - birkenfeld, JulienPalard -runtime lifecycle ericsnowcurrently, kumaraditya303, zooba +PEG parser gvanrossum, pablogsal, lysnikolaou +performance vstinner, serhiy-storchaka*, 1st1, rhettinger, markshannon, + brandtbucher, carljm, Fidget-Spinner, AlexWaygood*, nascheme +pip ncoghlan, dstufft, pfmoore, pradyunsg +release management malemburg, benjaminp, warsaw, + gvanrossum, merwok, ned-deily, + JulienPalard, hugovk +runtime lifecycle ericsnowcurrently, kumaraditya303, zooba, ZeroIntensity, nascheme, FFY00 str.format ericvsmith* -subinterpreters ericsnowcurrently, kumaraditya303 +subinterpreters ericsnowcurrently, kumaraditya303, ZeroIntensity* symbol table JelleZijlstra, carljm -testing voidspace, ezio-melotti +testing ezio-melotti test coverage threads gpshead -time and dates malemburg, abalkin, pganssle -unicode malemburg, ezio-melotti, benjaminp +time and dates malemburg, pganssle +Unicode malemburg, ezio-melotti, benjaminp version control merwok, ezio-melotti ================== ========================================================== +Experts emeritus +================ + +Names followed by a '^' indicate old bugs.python.org usernames, for people +that did not transition to GitHub. + +Stdlib +------ + +.. list-table:: + + * - Module + - Expert + + * - codecs + - doerwalter + + * - collections.abc + - stutzbach^ + + * - concurrent.futures + - brianquinlan + + * - copy + - avassalotti + + * - copyreg + - avassalotti + + * - csv + - smontanaro + + * - ctypes + - theller, abalkin, amauryfa, meadori + + * - datetime + - abalkin + + * - difflib + - tim-one + + * - doctest + - tim-one + + * - email + - maxking + + * - enum + - eliben + + * - heapq + - stutzbach + + * - idlelib + - kbkaiser, serwy + + * - io + - stutzbach^ + + * - ipaddress + - pmoody^ + + * - json + - etrepum + + * - math + - stutzbach^ + + * - modulefinder + - theller, jvr^ + + * - multiprocessing + - applio, jnoller^, sbt^ + + * - optparse + - mitsuhiko + + * - pickle + - avassalotti + + * - pickletools + - avassalotti + + * - pprint + - freddrake + + * - selectors + - neologix^ + + * - shutil + - tarekziade + + * - sqlite3 + - ghaering^ + + * - ssl + - jackjansen + + * - statistics + - stevendaprano + + * - struct + - meadori + + * - subprocess + - astrand^ + + * - syslog + - jafo^ + + * - tabnanny + - tim-one + + * - tarfile + - gustaebel + + * - time + - abalkin + + * - tkinter + - gpolo^ + + * - tokenize + - meadori + + * - trace + - abalkin + + * - turtle + - gregorlingl^ + + * - unittest + - rbtcollins + + * - weakref + - freddrake + + * - winreg + - stutzbach^ + + * - wsgiref + - pjenvey + + * - xml.etree + - eliben + + * - zipfile + - alanmcintyre^ + +Platforms +--------- + +.. list-table:: + + * - Platform + - Expert + + * - AIX + - edelsohn + + * - Cygwin + - jlt63^, stutzbach^ + + * - JVM/Java + - frank.wierzbicki^ + + * - OS2/EMX + - aimacintyre^ + + +Miscellaneous +------------- + +.. list-table:: + + * - Interest Area + - Expert + + * - filesystem + - giampaolo + + * - io + - stutzbach^ + + * - mathematics + - stutzbach^ + + * - networking + - giampaolo + + * - packaging + - tarekziade, alexis^ + + * - pip + - Marcus.Smith^ + + * - release management + - tarekziade, anthonybaxter^, birkenfeld + + * - time and dates + - abalkin + + Documentation translations ========================== -For a list of translators, see :ref:`this table about translations <translating>`. +Translations are within the charter of +`Editorial Board <https://python.github.io/editorial-board/>`__. +For a list of translations and their coordinators, see +:ref:`this table of translations <translation-coordinators>`. diff --git a/core-developers/index.rst b/core-team/index.rst similarity index 54% rename from core-developers/index.rst rename to core-team/index.rst index 8555943a07..f8dafe05ee 100644 --- a/core-developers/index.rst +++ b/core-team/index.rst @@ -1,8 +1,9 @@ .. _core-dev: +.. _core-team: -=============== -Core developers -=============== +========= +Core team +========= .. toctree:: :maxdepth: 5 @@ -10,6 +11,7 @@ Core developers responsibilities committing experts - developer-log + team-log motivations - become-core-developer + join-team + memorialization diff --git a/core-developers/become-core-developer.rst b/core-team/join-team.rst similarity index 67% rename from core-developers/become-core-developer.rst rename to core-team/join-team.rst index 739792b481..20ce9e4c98 100644 --- a/core-developers/become-core-developer.rst +++ b/core-team/join-team.rst @@ -1,24 +1,25 @@ .. _become-core-developer: .. _coredev: +.. _join-core-team: -============================== -How to become a core developer -============================== +========================= +How to join the core team +========================= What it takes ============= When you have consistently made contributions which meet quality standards without requiring extensive rewrites prior to being committed, -you may qualify for commit privileges and become a core developer of Python. -You must also work well with other core developers (and people in general) +you may qualify for commit privileges and join the core team of Python. +You must also work well with other core team members (and people in general) as you become an ambassador for the Python project. -Typically a core developer will offer you the chance to gain commit privilege. +Typically a core team member will offer you the chance to gain commit privilege. The person making the offer will become your mentor and watch your commits for a while to make sure you understand the development process. If other core developers agree that you should gain commit privileges you are then extended -an official offer. How core developers come to that agreement are outlined in +an official offer. How core team members come to that agreement are outlined in :pep:`13`. @@ -28,7 +29,7 @@ Gaining commit privileges After a candidate has demonstrated consistent contributions, commit privileges are granted through these steps: -#. A core developer (submitter, usually the mentor) starts a poll +#. A core team member (submitter, usually the mentor) starts a poll (see the :ref:`template <coredev-template>` below) in the `Committers category`_ on the `Python Discourse`_. @@ -38,13 +39,15 @@ are granted through these steps: #. If the candidate receives at least two-thirds positive votes when the poll closes (as per :pep:`13`), the submitter `emails the steering council <mailto:steering-council@python.org>`_ with the candidate's email address - requesting that the council either accept or reject the proposed membership. + requesting that the council either accept or reject the proposed membership. Technically, the + council may only `veto a positive vote <https://peps.python.org/pep-0013/#membership>`__. -#. Assuming the steering council does not object, a member of the council or delegate - (approver) will email the candidate: +#. Assuming the steering council does not veto the positive vote, a member of the council or its + delegate (approver, usually in practice a :ref:`Developer-in-Residence <current owners>`) will + email the candidate: - A request for account details as required by - `🔒 python/voters <https://github.com/python/voters>`_. + `🔒 python/voters <https://github.com/python/voters>`__. - A reminder about the `Code of Conduct`_ and guidance on reporting issues to the PSF Conduct WG. @@ -52,11 +55,12 @@ are granted through these steps: - Enable the various new privileges. - Remove the new committer from the triage team, if applicable. - - Add their details to `🔒 python/voters <https://github.com/python/voters>`_. - - Update the devguide to publicly list their team membership - at :ref:`developers`. + - Add their details to `🔒 python/voters <https://github.com/python/voters>`__. + - Once the python/voters update is merged, regenerate the public team membership + list at :ref:`developers`. + See "Public list of members" in the ``voters`` README. - Post an announcement in the `Committers Discourse category - <https://discuss.python.org/c/committers/5>`_. The past few announcements + <https://discuss.python.org/c/committers/5>`__. The past few announcements were in the form of a separate post on the already open topic with the poll. @@ -65,7 +69,7 @@ Getting a python.org email address Members of the core team can get an email address on the python.org domain. For more details refer to the `python.org email policy -<https://www.python.org/psf/records/board/policies/email/>`_. +<https://www.python.org/psf/records/board/policies/email/>`__. Poll template @@ -86,10 +90,11 @@ Here's what it outputs, you can copy and paste it for your poll: [/poll] The important options in the poll builder set to get this result: - - Show who voted: **disabled** (``public=false``) - - Limit voting to these groups: **committers** (``groups=committers``) - - Automatically close poll: **in 7 days** (``close=...``) - - Show results: **When poll is closed** (``results=on_close``) + +- Show who voted: **disabled** (``public=false``) +- Limit voting to these groups: **committers** (``groups=committers``) +- Automatically close poll: **in 7 days** (``close=...``) +- Show results: **When poll is closed** (``results=on_close``) .. raw:: html diff --git a/core-team/memorialization.rst b/core-team/memorialization.rst new file mode 100644 index 0000000000..3d893a3029 --- /dev/null +++ b/core-team/memorialization.rst @@ -0,0 +1,159 @@ +.. _memorialize-core-developer: +.. _memorialize-core-team-member: + +=============== +Memorialization +=============== + +Rationale +========= + +When a core team member passes away, memorializing accounts helps create +a space for remembering the contributor and protects against attempted +logins and fraudulent activity. + +The process +=========== + +The memorialization process is performed by a member of the PSF staff +with administrative access to current and historical systems where +the core team has access. + +After the status of the core team member in question is confirmed, +access to the systems listed below is revoked and some changes are +made to how the user displays to others. + +To respect the choices that someone made while alive, we aim to preserve +content of their accounts without changes after they've passed away. +To support the bereaved, in some instances, we may remove or change +certain content when the legacy contact or family members request it. + +GitHub +------ + +* The user is removed from the `python/ <https://github.com/orgs/python/>`__ + organization on GitHub; +* The user is removed from the `psf/ <https://github.com/orgs/psf/>`__ + organization on GitHub; +* The user is removed from the `pypa/ <https://github.com/orgs/pypa/>`__ + organization on GitHub. + +The PSF staff does not follow up with GitHub with regards to GitHub account +cancellation as this action is reserved for next-of-kin or designated by +the deceased GitHub user to act as an account successor. + +The general policy regarding deceased users on GitHub is described on their +`Deceased User Policy <https://docs.github.com/en/site-policy/other-site-policies/github-deceased-user-policy>`__ +page. + +Repositories in the organization +-------------------------------- + +* The user's GitHub handle is removed from ``/.github/CODEOWNERS``. + To see all that need action, perform + `this query <https://github.com/search?q=org%3Apython+path%3A**%2F.github%2FCODEOWNERS+USERNAME&type=code>`__. +* The user is marked as deceased in the private + `voters/python-core.toml <https://github.com/python/voters/blob/main/python-core.toml>`__ + file with the ``left=`` field set to the day of passing, if known. + +discuss.python.org +------------------ + +* The user's "custom status" is set to 🕊 ``in memoriam``; +* The user's "about me" is amended with ``$firstname passed away on $date. [In memoriam.]($in_memoriam_post_url)``; +* In the user's security "recently used devices" the staff member + chooses "Log out all"; +* In the user's permissions the staff member chooses "Deactivate account"; +* The user's trust level is reset to ``1: basic user`` (trust level 0 + doesn't allow links in "About Me"); +* The user's "associated accounts" (like GitHub) that provide an + alternative login method, are all disconnected; +* The user's API keys are revoked; +* The user's admin or moderator right is revoked; +* The user's primary email address is reset to + ``USERNAME@in-memoriam.invalid`` and secondary email addresses are + removed (this step requires the administrator to contact Discourse.org + staff via ``team@discourse.org``). + +The "in memoriam" Discourse topic mentioned above is best created by +a community member close to the deceased. + +The general best practice for deceased community members on +Discourse-powered forums is described on their +`Best practices for deceased community members <https://meta.discourse.org/t/best-practices-for-deceased-community-members/146210>`__ +page. + +python.org email account +------------------------ + +The PSF staff member emails ``postmaster@python.org`` to ask the email +administrator to: + +* remove SMTP access from ``USERNAME@python.org``; +* reset the password to POP3/IMAP for ``USERNAME@python.org``; +* disable email forwarding, if set up, for ``USERNAME@python.org`` and + leave a record permanently as "in memoriam" to avoid future account + name reuse; +* remove this email from all mailing lists under ``@python.org``; +* remove any known alternate emails for the same user from all mailing + lists under ``@python.org``. + +In case the email shutdown causes issues for the estate executors, the +PSF will reasonably try to help if contacted directly. + +python.org admin +---------------- + +* The user's account (``/admin/users/user``) is deactivated (NOT deleted) + and their staff and superuser status is unchecked; +* The user's password is reset to a long random string; +* The user's primary email address is set to + ``USERNAME@in-memoriam.invalid`` and set as unverified; +* The user's secondary email addresses are deleted; +* The user's API keys (both on the account and ``tastypie``) are deleted; +* The user's "I would like to be a PSF Voting Member" field is cleared. + +devguide.python.org +------------------- + +* The user is marked as deceased in `core-team.csv <https://github.com/python/devguide/blob/main/core-team/core-team.csv>`__; +* The user is removed from the `experts index <https://github.com/python/devguide/blob/main/core-team/experts.rst>`__. + +bugs.python.org +--------------- + +While the issue tracker was migrated to GitHub, the Roundup instance +is still up for historical purposes. + +* the PSF staff member logs into ``bugs.nyc1.psf.io``; +* the PSF staff member runs ``roundup-admin`` to set the user's email + address to ``USERNAME@in-memoriam.invalid``; +* the user's alternate emails are removed; +* the user's password is reset to a long random string; +* the PSF staff member removes any active login sessions from Postgres. + +Other PSF-related infrastructure +-------------------------------- + +* The PSF staff member notifies administrators of the Python Core Devs + Discord server to remove the user from the server. The PSF staff + does not follow up with Discord with regards to Discord account + cancellation. The general policy regarding deceased users on Discord + is available on their `Deceased or Incapacitated Users <https://support.discord.com/hc/en-us/articles/19872987802263--Deceased-or-Incapacitated-Users>`__ + page. + +* The user is removed from Salt configuration for the PSF infrastructure + in `/pillar/base/users <https://github.com/python/psf-salt/tree/main/pillar/base/users>`__ + that allows SSH access to PSF-controlled servers. + +* The user might have ran a buildbot worker. The PSF staff member will + look for that in the + `buildmaster-config <https://github.com/search?q=repo%3Apython%2Fbuildmaster-config%20USERNAME&type=code>`__ + repository. + +PyPI +---- + +* The PSF staff member notifies PyPI admins by emailing them at + ``admin@pypi.org`` to mark the user as inactive, remove their email + addresses, prohibit their password resets, and revoke all API keys. diff --git a/core-developers/motivations.rst b/core-team/motivations.rst similarity index 81% rename from core-developers/motivations.rst rename to core-team/motivations.rst index b19c3062b8..d0e5a0cc18 100644 --- a/core-developers/motivations.rst +++ b/core-team/motivations.rst @@ -4,22 +4,22 @@ Motivations and affiliations ============================ -CPython core developers participate in the core development process for a -variety of reasons. Being accepted as a core developer indicates that +CPython core team members participate in the core development process for a +variety of reasons. Being accepted as a core team member indicates that an individual is interested in acquiring those responsibilities, has the -ability to collaborate effectively with existing core developers, and has had +ability to collaborate effectively with existing core team members, and has had the time available to demonstrate both that interest and that ability. -This page allows core developers that choose to do so to provide more +This page allows core team members that choose to do so to provide more information to the rest of the Python community regarding their personal situation (such as their general location and professional affiliations), as well as any personal motivations that they consider particularly relevant. -Core developers that wish to provide this additional information add a new +Core team members that wish to provide this additional information add a new entry to the :ref:`published-motivations` section below. Guidelines relating to content and layout are included as comments in the source code for this page. -Core developers that are available for training, consulting, contract, or +Core team members who are available for training, consulting, contract, or full-time work, or are seeking crowdfunding support for their community contributions, may also choose to provide that information here (including linking out to commercial sites with the relevant details). @@ -32,7 +32,7 @@ For more information on the origins and purpose of this page, see Published entries ================= -The following core developers have chosen to provide additional details +The following core team members have chosen to provide additional details regarding their professional affiliations and (optionally) other reasons for participating in the CPython core development process: @@ -43,7 +43,7 @@ participating in the CPython core development process: Topic headings should be in the form of "Name (Country)" or "Name (Continent)" to help give some indication as to the geographic - distribution of core developers. + distribution of core team members. NOTE: The rest of these guidelines are highly provisional - we can evolve them as people add entries, and we decide on the style we like. The @@ -97,22 +97,22 @@ participating in the CPython core development process: .. topic:: Brett Cannon (Canada) - * Personal site: `snarky.ca <https://snarky.ca/>`_ + * Personal site: `snarky.ca <https://snarky.ca/>`__ * Microsoft (Software Developer) * Python Software Foundation (Fellow) .. topic:: Alyssa Coghlan (Australia) - * Personal site: `Curious Efficiency <https://www.curiousefficiency.org/>`_ + * Personal site: `Curious Efficiency <https://www.curiousefficiency.org/>`__ * `Extended bio <https://www.curiousefficiency.org/pages/about>`__ * Python Software Foundation (Fellow, Packaging Working Group) - * Element Labs/LM Studio (Python deployment engineer) + * Westpac (Principal Python Engineer) Alyssa began using Python as a testing and prototyping language while working - for Boeing Defence Australia. She now primarily uses it as the lead project - maintainer for the open source ``venvstacks`` Python deployment utility. + for Boeing Defence Australia, and now works for Westpac, supporting their + use of Python for a range of purposes. - As a core developer, she is primarily interested in helping to ensure Python's + As a core team member, she is primarily interested in helping to ensure Python's continued suitability for educational, testing and data analysis use cases, as well as in encouraging good architectural practices when assembling Python applications and test harnesses from open source components. @@ -123,16 +123,16 @@ participating in the CPython core development process: .. topic:: Steve Dower (United States/Australia) * Microsoft (Software Developer) - * Personal site: `stevedower.id.au <https://stevedower.id.au/>`_ - * Speaking: `stevedower.id.au/speaking <https://stevedower.id.au/speaking>`_ - * Work blog: `devblogs.microsoft.com/python/ <https://devblogs.microsoft.com/python/>`_ + * Personal site: `stevedower.id.au <https://stevedower.id.au/>`__ + * Speaking: `stevedower.id.au/speaking <https://stevedower.id.au/speaking>`__ + * Work blog: `devblogs.microsoft.com/python/ <https://devblogs.microsoft.com/python/>`__ * Email address: steve.dower@python.org Steve started with Python while automating a test harness for medical devices, and now works for Microsoft on anything that makes Python more accessible to developers on any platform. - As a core developer, his focus is on maintaining the already excellent + As a core team member, his focus is on maintaining the already excellent Windows support and improving Python's ability to be embedded in other applications. @@ -143,25 +143,25 @@ participating in the CPython core development process: .. topic:: Mariatta (Canada) - * Personal site: `mariatta.ca <https://mariatta.ca>`_ - * Works as a `Software Engineer <https://www.linkedin.com/in/mariatta/>`_ + * Personal site: `mariatta.ca <https://mariatta.ca>`__ + * Works as a `Software Engineer <https://www.linkedin.com/in/mariatta/>`__ in Vancouver, helps organize `Vancouver PyLadies - <https://www.meetup.com/PyLadies-Vancouver/>`_ meetup on the side, and - sometimes `speaks <https://mariatta.ca/posts/talks/>`_ + <https://www.meetup.com/PyLadies-Vancouver/>`__ meetup on the side, and + sometimes `speaks <https://mariatta.ca/posts/talks/>`__ at conferences. * Email address: mariatta@python.org - * `Sponsor Mariatta on GitHub <https://github.com/sponsors/Mariatta>`_ - * `Patreon <https://www.patreon.com/Mariatta>`_ + * `Sponsor Mariatta on GitHub <https://github.com/sponsors/Mariatta>`__ + * `Patreon <https://www.patreon.com/Mariatta>`__ - Support Mariatta by `becoming a sponsor <https://github.com/sponsors/Mariatta>`_, - sending her a `happiness packet <https://www.happinesspackets.io/send/>`_, - or `paypal <https://www.paypal.com/paypalme/mariatta>`_. + Support Mariatta by `becoming a sponsor <https://github.com/sponsors/Mariatta>`__, + sending her a `happiness packet <https://www.happinesspackets.io/send/>`__, + or `paypal <https://www.paypal.com/paypalme/mariatta>`__. .. topic:: R. David Murray (United States) - * Personal site: `bitdance.com <https://www.bitdance.com>`_ + * Personal site: `bitdance.com <https://www.bitdance.com>`__ * Available for `Python and Internet Services Consulting - and Python contract programming <https://www.murrayandwalker.com/>`_ + and Python contract programming <https://www.murrayandwalker.com/>`__ David has been involved in the Internet since the days when the old IBM BITNET and the ARPANet got cross connected, and in Python programming since @@ -177,7 +177,7 @@ participating in the CPython core development process: David currently does both proprietary and open source development work, primarily in Python, through the company in which he is a partner, `Murray & - Walker, Inc <https://www.murrayandwalker.com>`_. He has done contract work + Walker, Inc <https://www.murrayandwalker.com>`__. He has done contract work focused specifically on CPython development both through the PSF (the kickstart of the email Unicode API development) and directly funded by interested corporations (additional development work on email funded by @@ -187,14 +187,14 @@ participating in the CPython core development process: .. topic:: Antoine Pitrou (France) - * LinkedIn: `<https://www.linkedin.com/in/pitrou/>`_ (Senior Software Engineer) + * LinkedIn: `<https://www.linkedin.com/in/pitrou/>`__ (Senior Software Engineer) * QuantStack * Python Software Foundation (Fellow) * Email address: antoine@python.org Antoine started working with Python in 2005 in order to implement a decentralized virtual world protocol. He started contributing to CPython - in 2007 and became a core developer in 2008. His motivations have been + in 2007 and became a core team member in 2008. His motivations have been driven both by the abstract desire to make Python better for the whole world, and by the concrete roadblocks he was hitting in professional settings. Topics of choice have included interpreter optimizations, @@ -213,7 +213,7 @@ participating in the CPython core development process: Victor is paid by Red Hat to maintain Python upstream and downstream (RHEL, CentOS, Fedora & Software collections). See `Victor's contributions to - Python <https://vstinner.readthedocs.io/python_contrib.html>`_. + Python <https://vstinner.readthedocs.io/python_contrib.html>`__. .. topic:: Kushal Das (India) @@ -224,21 +224,21 @@ participating in the CPython core development process: .. topic:: Barry Warsaw (United States) * NVIDIA, Principal System Software Engineer, Open Source Python Ecosystem - * Personal site: `barry.warsaw.us <https://barry.warsaw.us/>`_ - * Blog: `We Fear Change <https://www.wefearchange.org/>`_ - * `LinkedIn <https://www.linkedin.com/in/barry-warsaw/>`_ - * `Bluesky <https://bsky.app/profile/pumpichank.bsky.social>`_ + * Personal site: `barry.warsaw.us <https://barry.warsaw.us/>`__ + * Blog: `We Fear Change <https://www.wefearchange.org/>`__ + * `LinkedIn <https://www.linkedin.com/in/barry-warsaw/>`__ + * `Bluesky <https://bsky.app/profile/pumpichank.bsky.social>`__ * Email address: barry@python.org * Python Software Foundation (Fellow) Barry has been working in, with, and on Python since 1994. He attended the - first Python workshop at `NIST <https://www.nist.gov/>`_ in Gaithersburg, + first Python workshop at `NIST <https://www.nist.gov/>`__ in Gaithersburg, MD in 1994, where he met Guido and several other early Python adopters. Barry subsequently worked with Guido for 8 years while at `CNRI - <http://cnri.reston.va.us/>`_. Barry has served as Python's postmaster, + <http://cnri.reston.va.us/>`__. Barry has served as Python's postmaster, webmaster, release manager, Language Summit co-chair, `Jython - <https://www.jython.org/>`_ project leader, `GNU Mailman - <https://www.list.org/>`_ project leader, and Python Steering Council + <https://www.jython.org/>`__ project leader, `GNU Mailman + <https://www.list.org/>`__ project leader, and Python Steering Council member in 2019, 2020, 2021, 2024, and 2025. .. topic:: Eric Snow (United States) @@ -256,13 +256,13 @@ participating in the CPython core development process: developers on the project for 6 years. After that he started the Python Tools for Visual Studio project focusing on providing advanced code completion and debugging features for Python. Today he works on - `Cinder <https://github.com/facebookincubator/cinder/>`_ improving Python + `Cinder <https://github.com/facebookincubator/cinder/>`__ improving Python performance for Instagram. .. topic:: Carol Willing (United States) * Noteable (VP Engineering) - * Personal site: `Willing Consulting <https://www.willingconsulting.com/>`_ + * Personal site: `Willing Consulting <https://www.willingconsulting.com/>`__ * `Extended bio <https://www.willingconsulting.com/about/>`__ * Project Jupyter (Software Council, Core Team for JupyterHub/Binder) * Python Software Foundation (Fellow) @@ -279,12 +279,12 @@ Goals of this page The `issue metrics`_ automatically collected by the CPython issue tracker strongly suggest that the current core development process is bottlenecked on -core developer time. This is most clearly indicated in the first metrics graph, +core team time. This is most clearly indicated in the first metrics graph, which shows both the number of open issues and the number of pull requests awaiting review growing steadily over time, despite CPython being one of the most active open source projects in the world. This bottleneck then impacts not only resolving open issues and accepting submitted pull requests, but also the process of -identifying, nominating and mentoring new core developers. +identifying, nominating and mentoring new core team members. The core commit statistics monitored by sites like `OpenHub`_ provide a good record as to *who* is currently handling the bulk of the review and maintenance @@ -293,13 +293,13 @@ people's ability to spend time on reviewing proposed changes, or mentoring new contributors. This page aims to provide at least some of that missing data by encouraging -core developers to highlight professional affiliations in the following two +core team members to highlight professional affiliations in the following two cases (even if not currently paid for time spent participating in the core development process): -* developers working for vendors that distribute a commercially supported +* members working for vendors that distribute a commercially supported Python runtime -* developers working for Sponsor Members of the Python Software Foundation +* members working for Sponsor Members of the Python Software Foundation These are cases where documenting our affiliations helps to improve the overall transparency of the core development process, as well as making it @@ -307,20 +307,20 @@ easier for staff at these organisations to locate colleagues that can help them to participate in and contribute effectively to supporting the core development process. -Core developers working for organisations with a vested interest in the +Core team members working for organisations with a vested interest in the sustainability of the CPython core development process are also encouraged to seek opportunities to spend work time on mentoring potential new core developers, whether through the general `core mentorship program`_, through mentoring colleagues, or through more targeted efforts like Outreachy's paid `internships`_ and Google's `Summer of Code`_. -Core developers that are available for consulting or contract work on behalf of +Core team members who are available for consulting or contract work on behalf of the Python Software Foundation or other organisations are also encouraged to provide that information here, as this will help the PSF to better facilitate funding of core development work by organisations that don't -directly employ any core developers themselves. +directly employ any core team members themselves. -Finally, some core developers seeking to increase the time they have available +Finally, some core team members seeking to increase the time they have available to contribute to CPython may wish to pursue crowdfunding efforts that allow their contributions to be funded directly by the community, rather than relying on institutional sponsors allowing them to spend some or all of their work @@ -336,15 +336,15 @@ time contributing to CPython development. Limitations on scope ==================== -* Specific technical areas of interest for core developers should be captured in +* Specific technical areas of interest for core team members should be captured in the :ref:`Experts Index <experts>`. -* This specific listing is limited to CPython core developers (since it's - focused on the specific constraint that is core developer time), but it +* This specific listing is limited to CPython core team members (since it's + focused on the specific constraint that is core team member time), but it would be possible to create a more expansive listing on the Python wiki that - also covers issue triagers, and folks seeking to become core developers. + also covers issue triagers, and folks seeking to join the core team. -* Changes to the software and documentation maintained by core developers, +* Changes to the software and documentation maintained by the core team, together with related design discussions, all take place in public venues, and hence are inherently subject to full public review. Accordingly, core developers are NOT required to publish their motivations and affiliations if diff --git a/core-developers/responsibilities.rst b/core-team/responsibilities.rst similarity index 84% rename from core-developers/responsibilities.rst rename to core-team/responsibilities.rst index 5cd5ed7bdb..9f5c62b728 100644 --- a/core-developers/responsibilities.rst +++ b/core-team/responsibilities.rst @@ -5,25 +5,25 @@ Responsibilities ================ As contributors to the CPython project, our shared responsibility is to -collaborate constructively with other contributors, including core developers. +collaborate constructively with other contributors, including core team members. This responsibility covers all forms of contribution, whether that's submitting pull requests to the implementation or documentation, reviewing other peoples' pull requests, triaging issues on the issue tracker, or discussing design and development ideas on the core :ref:`communication channels <communication-channels>`. -Core developers accept key additional responsibilities around the ongoing +Core team members accept key additional responsibilities around the ongoing management of the project: -* core developers bear the additional responsibility of handling the +* core team members bear the additional responsibility of handling the consequences of accepting a change into the code base or documentation. That includes reverting or fixing it if it causes problems in the Buildbot fleet or someone spots a problem in post-commit review, as well as helping out the release manager in resolving any problems found during the pre-release testing cycle. While all contributors are free to help out with this part of the process, and it is most welcome when they do, the - actual responsibility rests with the core developer that merged the change -* core developers also bear the primary responsibility for deciding when + actual responsibility rests with the core team member that merged the change +* core team members also bear the primary responsibility for deciding when changes proposed on the issue tracker should be escalated to the appropriate :ref:`Discourse <communication-discourse>` category for wider discussion, as well as suggesting the use of the @@ -31,15 +31,15 @@ management of the project: of complex changes, or changes with a potentially significant impact on end users -As a result of the additional responsibilities they accept, core developers +As a result of the additional responsibilities they accept, core team members gain the privilege of being able to approve proposed changes, as well as being -able to reject them as inappropriate. Core developers are also able to request +able to reject them as inappropriate. Core team members are also able to request that even already merged changes be escalated to :ref:`Discourse <communication-discourse>` for further discussion, and potentially even reverted prior to release. -Becoming a core developer isn't a binary "all-or-nothing" status - CPython -is a large project, and different core developers accept responsibility for +Joining the core team isn't a binary "all-or-nothing" status - CPython +is a large project, and different core team members accept responsibility for making design and development decisions in different areas (as documented in the :ref:`experts` and :ref:`developers`). @@ -48,12 +48,12 @@ Communication channels and bug notifications ============================================ Mailing lists have generally been replaced by the -`Discourse forum <https://discuss.python.org/>`_ (``discuss.python.org``). +`Discourse forum <https://discuss.python.org/>`__ (``discuss.python.org``). Refer to the :ref:`mailinglists` and :ref:`communication-discourse` sections for more information. If you want notification of new issues, you can use the appropriate GitHub notification -settings for the `python/cpython <https://github.com/python/cpython>`_ repository — +settings for the `python/cpython <https://github.com/python/cpython>`__ repository — follow the link and click on the :guilabel:`Watch` button to set your notification options. @@ -82,7 +82,7 @@ Pull request merging Once you have your commit privileges on GitHub you will be able to accept pull requests on GitHub. You should plan to continue to submit your own -changes through pull requests as if you weren't a core developer to benefit +changes through pull requests as if you weren't a core team member to benefit from various things such as automatic integration testing, but you can accept your own pull requests if you feel comfortable doing so. @@ -90,13 +90,13 @@ can accept your own pull requests if you feel comfortable doing so. Expectations ============ -As a core developer, there are certain things that are expected of you. +As a core team member, there are certain things that are expected of you. First and foremost, be a good person. This might sound melodramatic, but you are now a member of the Python project and thus represent the project and your -fellow core developers whenever you discuss Python with anyone. We have a +fellow core team members whenever you discuss Python with anyone. We have a reputation for being a very nice group of people and we would like to keep it -that way. Core developers responsibilities include following the `PSF Code of +that way. Core team responsibilities include following the `PSF Code of Conduct`_. Second, please be prompt in responding to questions. Many contributors to Python @@ -118,7 +118,7 @@ remove yourself from the list. Fourth, please consider whether or not you wish to add your name to the :ref:`motivations` list. Core contributor participation in the list helps the wider Python community to better appreciate the perspectives currently -represented amongst the core development team, the Python Software Foundation +represented amongst the core team, the Python Software Foundation to better assess the sustainability of current contributions to CPython core development, and also serves as a referral list for organisations seeking commercial Python support from the core development community. diff --git a/core-developers/developer-log.rst b/core-team/team-log.rst similarity index 85% rename from core-developers/developer-log.rst rename to core-team/team-log.rst index 665ef07003..77639ebf1d 100644 --- a/core-developers/developer-log.rst +++ b/core-team/team-log.rst @@ -1,16 +1,17 @@ .. _developer-log: .. _developers: +.. _team-log: -Developer log -============= +Team log +======== -This page lists the historical members of the Python development team. (The +This page lists the historical members of the Python core team. (The master list is kept in a private repository due to containing sensitive contact information.) .. csv-table:: :header: "Name", "GitHub username", "Joined", "Left", "Notes" - :file: developers.csv + :file: core-team.csv :encoding: "utf-8" Procedure for granting or dropping access diff --git a/developer-workflow/c-api.rst b/developer-workflow/c-api.rst index 3f8c03e92c..427d9fd96a 100644 --- a/developer-workflow/c-api.rst +++ b/developer-workflow/c-api.rst @@ -19,8 +19,13 @@ The C API is divided into these tiers: Each tier has different stability and maintenance requirements to consider when you add or change definitions in it. -The compatibility guarantees for public C API are explained in the -user documentation, ``Doc/c-api/stable.rst`` (:ref:`python:stable`). +The public backwards compatibility guarantees for public C API are explained +in the user documentation, ``Doc/c-api/stable.rst`` (:ref:`python:stable`). +C language compatibility guarantees are in ``Doc/c-api/intro.rst`` +(:ref:`python:api-intro`). + +As core developers, we need to be more careful about compatibility than what +we promise publicly. See :ref:`public-capi` for details. The internal API @@ -33,7 +38,7 @@ While internal API can be changed at any time, it's still good to keep it stable: other API or other CPython developers may depend on it. For users, internal API is sometimes the best workaround for a thorny problem --- though those use cases should be discussed on the -`C API Discourse category <https://discuss.python.org/c/30>`_ +`C API Discourse category <https://discuss.python.org/c/30>`__ or an issue so we can try to find a supported way to serve them. @@ -93,6 +98,17 @@ CPython's public C API is available when ``Python.h`` is included normally It should be defined in ``Include/cpython/`` (unless part of the Limited API, see below). +Before adding new public API, please ask in the `decisions repo`_ of +the :pep:`C API workgroup <731>`. +This helps us ensure *newly added* API is consistent and maintainable. + +Also check with the C API WG before requiring a C feature not present in C99. +While the *public* docs only promise compatibility with C11, in practice +we only introduce C11 features individually as needed. + +.. _decisions repo: https://github.com/capi-workgroup/decisions/issues + + .. _public-api-guidelines: Guidelines for expanding/changing the public API @@ -202,7 +218,7 @@ use this API reliably: (:samp:`3.{x}.0`, including Alphas and Betas for :samp:`3.{x}.0`). * Adding a new unstable API *for an existing feature* is allowed even after Beta feature freeze, up until the first Release Candidate. - Consensus on the `Core Development Discourse <https://discuss.python.org/c/core-dev/23>`_ + Consensus on the `Core Development Discourse <https://discuss.python.org/c/core-dev/23>`__ is needed in the Beta period. * Backwards-incompatible changes should make existing C callers fail to compile. For example, arguments should be added/removed, or a function should be @@ -371,7 +387,7 @@ Guidelines for adding to the Limited API details involve: - The GIL - - :ref:`Garbage collection <gc>` + - Garbage collection - Memory layout of PyObject, lists/tuples and other structures If following these guidelines would hurt performance, add a fast function @@ -379,9 +395,8 @@ If following these guidelines would hurt performance, add a fast function API. If anything is unclear, or you have a good reason to break the guidelines, -consider discussing the change at the `capi-sig`_ mailing list. - -.. _capi-sig: https://mail.python.org/mailman3/lists/capi-sig.python.org/ +consider discussing the change in the `C API category +<https://discuss.python.org/c/core-dev/c-api/>`__ on Discourse. Adding a new definition to the Limited API ------------------------------------------ diff --git a/developer-workflow/communication-channels.rst b/developer-workflow/communication-channels.rst index 499ca9b964..78fbf21dff 100644 --- a/developer-workflow/communication-channels.rst +++ b/developer-workflow/communication-channels.rst @@ -27,12 +27,13 @@ in return. Mailing lists ============= -.. note:: Some mailing lists have been supplanted by categories in the - Python `Discourse`_. Specifically, +.. note:: + + Mailing lists have generally been replaced by the `Discourse`_ forum. + Specifically, * The python-dev list is superseded by the `Core Development`_ and `PEPs`_ categories on Discourse. - * The python-ideas list is superseded by posts in the `Ideas`_ category on Discourse. @@ -42,36 +43,33 @@ Mailing lists - Ideas about new functionality should **not** start here, and instead should be discussed in `Ideas`_. - Technical support questions should also not be asked here, and instead - should go to the python-list_ or python-help_ mailing lists, or the - `Python Help`_ category on Discourse. + should go to the `Python Help`_ category on Discourse or the python-list_. -Existing threads on the python-dev_, python-committers_, and python-ideas_ mailing lists -can be accessed through the `online archive <web gateway_>`__. + Previous threads on the python-dev_, python-committers_, and python-ideas_ + mailing lists can be accessed through the `online archive + <https://mail.python.org/archives/>`__. + + .. _python-committers: https://mail.python.org/mailman3/lists/python-committers.python.org/ + .. _python-dev: https://mail.python.org/mailman3/lists/python-dev.python.org/ + .. _python-ideas: https://mail.python.org/archives/list/python-ideas@python.org/ General Python questions should go to `python-list`_ or `tutor`_ -or similar resources, such as StackOverflow_ or the ``#python`` IRC channel +or similar resources, such as `Stack Overflow`_ or the ``#python`` IRC channel on Libera.Chat_. -`The core-workflow <https://github.com/python/core-workflow/issues>`_ +The `core-workflow <https://github.com/python/core-workflow/issues>`__ issue tracker is the place to discuss and work on improvements to the CPython core development workflow. A complete list of Python mailing lists can be found at -https://mail.python.org/mailman/listinfo (older lists, using Mailman2) or -https://mail.python.org/mailman3/ (newer lists, using Mailman3). Some lists may also -be mirrored at `GMANE <https://gmane.io/>`_ and can be read and posted to in various +https://mail.python.org/mailman3/. Some lists may also +be mirrored at `GMANE <https://gmane.io/>`__ and can be read and posted to in various ways, including via web browsers, NNTP newsreaders, and RSS feed readers. -.. _issue tracker: https://github.com/python/cpython/issues -.. _python-committers: https://mail.python.org/mailman3/lists/python-committers.python.org/ -.. _python-dev: https://mail.python.org/mailman3/lists/python-dev.python.org/ -.. _python-help: https://mail.python.org/mailman/listinfo/python-help -.. _python-ideas: https://mail.python.org/mailman3/lists/python-ideas.python.org -.. _python-list: https://mail.python.org/mailman/listinfo/python-list -.. _tutor: https://mail.python.org/mailman/listinfo/tutor -.. _StackOverflow: https://stackoverflow.com/ +.. _python-list: https://mail.python.org/mailman3/lists/python-list.python.org/ +.. _tutor: https://mail.python.org/mailman3/lists/tutor.python.org/ +.. _Stack Overflow: https://stackoverflow.com/ .. _Libera.Chat: https://libera.chat/ -.. _web gateway: https://mail.python.org/archives/ .. _communication-discourse: @@ -79,19 +77,16 @@ ways, including via web browsers, NNTP newsreaders, and RSS feed readers. Discourse (discuss.python.org web forum) ======================================== -We have our own `Discourse`_ forum for both developers and users. This forum -complements the `python-dev`_, `python-ideas`_, `python-help`_, and -`python-list`_ mailing lists. - -This forum has different categories and most core development discussions +We have our own `Discourse`_ forum for both developers and users. +It has different categories and most core development discussions take place in the open forum categories for `PEPs`_ and `Core Development`_ (these are the Discourse equivalents to the python-dev mailing list). All categories are open for users to read and post with the exception of the `Committers`_ category, where posting is restricted to the `CPython -<https://github.com/python/cpython>`_ core developers. +<https://github.com/python/cpython>`__ core team. The Committers category is often used for announcements and notifications. -It is also the designated venue for the core developer promotion votes. +It is also the designated venue for the core team promotion votes. Tutorials for new users ----------------------- @@ -101,8 +96,8 @@ create an account using an email address or GitHub account. You can do so by clicking the :guilabel:`Sign Up` button on the top right hand corner of the `Discourse`_ main page. -The Python Discourse `Quick Start <https://discuss.python.org/t/python-discourse-quick-start/116>`_ -compiled by `Carol Willing <https://discuss.python.org/u/willingc/>`_ gives you +The Python Discourse `Quick Start <https://discuss.python.org/t/python-discourse-quick-start/116>`__ +compiled by `Carol Willing <https://discuss.python.org/u/willingc/>`__ gives you a quick overview on how to kick off Python Discourse. We recommend new users getting familiarised with the forum by going through Discobot tutorials. @@ -118,13 +113,13 @@ Greetings!" received under Notifications and Messages in your user account. * Select either Notifications or Messages. * Open the "Greetings!" message sent by Discobot to start the tutorial. -Ensure that you read through the `Python Code of Conduct <https://discuss.python.org/faq>`_. +Ensure that you read through the `Python Code of Conduct <https://discuss.python.org/faq>`__. We are to be open, considerate and respectful to all users in the community. You can report messages that don't respect the CoC by clicking on the three dots under the message and then on the :guilabel:`⚐` icon. You can also mention the -`@staff <https://discuss.python.org/groups/staff>`_, -`@moderators <https://discuss.python.org/groups/moderators>`_, or -`@admins <https://discuss.python.org/groups/admins>`_ groups in a message. +`@staff <https://discuss.python.org/groups/staff>`__, +`@moderators <https://discuss.python.org/groups/moderators>`__, or +`@admins <https://discuss.python.org/groups/admins>`__ groups in a message. @@ -168,7 +163,7 @@ Customising notifications on user preference ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To get a bird's eye view of all your customised notifications, you can -go to `Preferences of your account <https://discuss.python.org/my/preferences/categories>`_. +go to `Preferences of your account <https://discuss.python.org/my/preferences/categories>`__. This allows you to make adjustments according to categories, users, and tags. Enabling mailing list mode @@ -178,7 +173,7 @@ In mailing list mode, you will receive one email per post, as happens with traditional mailing lists. This is desirable if you prefer to interact via email, without visiting the forum website. To activate the mailing list mode, go to the `email preferences -<https://discuss.python.org/my/preferences/emails>`_, check "Enable +<https://discuss.python.org/my/preferences/emails>`__, check "Enable mailing list mode" and save changes. .. _Discourse: https://discuss.python.org/ @@ -193,22 +188,22 @@ Discord (private chat server) ============================= For more real-time discussions, the core development team have a private Discord -server available. Core developers, Steering Council members, triagers, and +server available. Core team members, Steering Council members, triagers, and documentarians on the project are eligible to join the server. Joining the Discord server is entirely optional, as all essential communications occur on the mailing lists and Discourse forums. -For core developers, a long lived multiple use invitation link for this server -can be found in the private core developer only section of the Discourse forum. +For core team members, a long-lived multiple-use invitation link for this server +can be found in the private core team only section of the Discourse forum. For triagers and documentarians joining the Discord server, a single use invitation link should be generated and sent to them directly. When first joining the server, new users will only have access to the ``#welcome`` and ``#rules-and-info`` channels. To link their Discord ID with their project -role, core developers may update their Steering Council 🔒 `voter record`_ with +role, core team members may update their Steering Council 🔒 `voter record`_ with their Discord ID before posting in the ``#welcome`` channel to request access -to the rest of the server channels. Triagers, documentarians, and core developers +to the rest of the server channels. Triagers, documentarians, and core team members that would prefer not to add their Discord ID to their Steering Council voter record may instead be vouched for by an existing member of the Discord server. @@ -229,7 +224,7 @@ set a specific `Server Nickname`_ IRC === -Some core developers still participate in the ``#python-dev`` IRC channel on +Some core team members still participate in the ``#python-dev`` IRC channel on ``irc.libera.chat``. This is not a place to ask for help with Python, but to discuss issues related to Python's own development. See also the ``#python-dev-notifs`` channel for bots notifications. @@ -238,7 +233,7 @@ discuss issues related to Python's own development. See also the Blogs ===== -Several core developers are active bloggers and discuss Python's development +Several core team members are active bloggers and discuss Python's development that way. You can find their blogs (and various other developers who use Python) at `Planet Python <https://planetpython.org/>`__. @@ -247,22 +242,23 @@ Setting expectations for open source participation ================================================== Burn-out is common in open source due to a misunderstanding of what users, contributors, -and maintainers should expect from each other. Brett Cannon gave a `talk <https://www.youtube.com/watch?v=-Nk-8fSJM6I>`_ +and maintainers should expect from each other. Brett Cannon gave a `talk <https://www.youtube.com/watch?v=-Nk-8fSJM6I>`__ about this topic that sets out to help everyone set reasonable expectations of each other in order to make open source pleasant for everyone involved. Additional repositories ======================= -`Python Core Workflow`_ hosts the codebase for tools such as :pypi:`blurb`. +`Python Core Workflow`_ hosts an issue tracker for workflow discussions. -Other core workflow tools are: +Some core workflow tools are: * `cherry_picker`_ (:pypi:`PyPI <cherry_picker>`) * `bedevere`_ +* `blurb`_ (:pypi:`PyPI <blurb>`) * `blurb_it`_ * `miss-islington`_ -* `cla-bot`_ +* `clabot`_ * `webhook-mailer`_ Python `Performance Benchmark`_ project is intended to be an authoritative @@ -271,8 +267,9 @@ source of benchmarks for all Python implementations. .. _Python Core Workflow: https://github.com/python/core-workflow .. _cherry_picker: https://github.com/python/cherry-picker .. _bedevere: https://github.com/python/bedevere +.. _blurb: https://github.com/python/blurb .. _blurb_it: https://github.com/python/blurb_it .. _miss-islington: https://github.com/python/miss-islington -.. _cla-bot: https://github.com/ambv/cla-bot +.. _clabot: https://github.com/psf/clabot .. _webhook-mailer: https://github.com/python/webhook-mailer .. _Performance Benchmark: https://github.com/python/pyperformance diff --git a/developer-workflow/development-cycle.rst b/developer-workflow/development-cycle.rst index 8a37692ad6..af198a4007 100644 --- a/developer-workflow/development-cycle.rst +++ b/developer-workflow/development-cycle.rst @@ -4,7 +4,7 @@ Development cycle ================= -The responsibilities of a core developer shift based on what kind of branch of +The responsibilities of a core team member shift based on what kind of branch of Python a developer is working on and what stage the branch is in. To clarify terminology, Python uses a ``major.minor.micro`` nomenclature @@ -68,8 +68,8 @@ Maintenance branches A branch for a previous feature release, currently being maintained for bug fixes, or for the next feature release in its :ref:`beta <beta>` or :ref:`release candidate <rc>` stages. -There is usually either one or two maintenance branches at any given time for -Python 3.x. After the final release of a new minor version (3.x.0), releases +There are usually either one or two maintenance branches at any given time. +After the final release of a new minor version (3.x.0), releases produced from a maintenance branch are called **bugfix** or **maintenance** releases; the terms are used interchangeably. These releases have a **micro version** number greater than zero. @@ -134,7 +134,7 @@ former branch, for example, ``3.8`` or ``2.7``. The :ref:`versions` page contains list of active and end-of-life branches. The latest release for each Python version can be found on the `download page -<https://www.python.org/downloads/>`_. +<https://www.python.org/downloads/>`__. .. _stages: @@ -142,7 +142,7 @@ Stages ------ Based on what stage the :ref:`in-development <indevbranch>` version of Python -is in, the responsibilities of a core developer change in regards to commits +is in, the responsibilities of a core team member change in regards to commits to the :abbr:`VCS (version control system)`. @@ -159,7 +159,7 @@ avoiding breaking the buildbots). Alpha ^^^^^ -Alpha releases typically serve as a reminder to core developers that they +Alpha releases typically serve as a reminder to the core team that they need to start getting in changes that change semantics or add something to Python as such things should not be added during a Beta_. Otherwise no new restrictions are in place while in alpha. @@ -171,16 +171,13 @@ Beta After a first beta release is published, no new features are accepted. Only bug fixes and improvements to documentation and tests can now be committed. -This is when core developers should concentrate on the task of fixing +This is when the core team should concentrate on the task of fixing regressions and other new issues filed by users who have downloaded the alpha and beta releases. Being in beta can be viewed much like being in RC_ but without the extra overhead of needing commit reviews. -Please see the note in the `In-development (main) branch`_ section above for -new information about the creation of the 3.5 maintenance branch during beta. - .. _rc: @@ -188,18 +185,18 @@ Release Candidate (RC) ^^^^^^^^^^^^^^^^^^^^^^ A branch preparing for an RC release can only have bugfixes applied that have -been reviewed by other core developers. Generally, these issues must be +been reviewed by other core team members. Generally, these issues must be severe enough (for example, crashes) that they deserve fixing before the final release. All other issues should be deferred to the next development cycle, since stability is the strongest concern at this point. -While the goal is to have no code changes between a RC and a final release, +While the goal is to have no code changes between an RC and a final release, there may be a need for final documentation or test fixes. Any such proposed changes should be discussed first with the release manager. You **cannot** skip the peer review during an RC, no matter how small! Even if it is a simple copy-and-paste change, **everything** requires peer review from -a core developer. +a core team member. .. _final: @@ -207,36 +204,38 @@ Final ^^^^^ When a final release is being cut, only the release manager (RM) can make -changes to the branch. After the final release is published, the full -:ref:`development cycle <stages>` starts again for the next minor version. +changes to the branch. Repository administration ------------------------- The source code is currently hosted on `GitHub -<https://github.com/python/cpython>`_ in the `Python organization <https://github.com/python/>`_. +<https://github.com/python/cpython>`__ in the `Python organization <https://github.com/python/>`__. Organization repository policy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Within the `GitHub Python organization <https://github.com/python/>`_, +Within the `GitHub Python organization <https://github.com/python/>`__, repositories are expected to relate to the Python language, the CPython reference implementation, their documentation and their development workflow. This includes, for example: -* The reference implementation of Python and related repositories: `CPython <https://github.com/python/cpython>`_. -* Tooling and support around CPython development: `pyperformance <https://github.com/python/pyperformance>`_, `Bedevere <https://github.com/python/bedevere>`_. -* Helpers and backports for Python/CPython features: `typing_extensions <https://github.com/python/typing_extensions>`_, `typeshed <https://github.com/python/typeshed>`_, `tzdata <https://github.com/python/tzdata>`_, `pythoncapi-compat <https://github.com/python/pythoncapi-compat>`_. -* Organization-related repositories: the `Code of Conduct <https://github.com/python/pycon-code-of-conduct>`_, `.github <https://github.com/python/.github>`_. -* Documentation and websites for all the above: `python.org repository <https://github.com/python/pythondotorg>`_, `PEPs <https://github.com/python/peps>`_, `Devguide <https://github.com/python/devguide>`_, docs translations. -* Infrastructure for all the above: `docsbuild-scripts <https://github.com/python/docsbuild-scripts>`_, `buildmaster-config <https://github.com/python/buildmaster-config>`_. -* Discussions and notes around official development-related processes and events: `steering-council <https://github.com/python/steering-council>`_, `core-sprint <https://github.com/python/core-sprint>`_. +* The reference implementation of Python and related repositories: `CPython <https://github.com/python/cpython>`__. +* Tooling and support around CPython development: `pyperformance <https://github.com/python/pyperformance>`__, `Bedevere <https://github.com/python/bedevere>`__. +* Helpers and backports for Python/CPython features: `typing_extensions <https://github.com/python/typing_extensions>`__, `typeshed <https://github.com/python/typeshed>`__, `tzdata <https://github.com/python/tzdata>`__, `pythoncapi-compat <https://github.com/python/pythoncapi-compat>`__. +* Organization-related repositories: the `Code of Conduct <https://github.com/python/pycon-code-of-conduct>`__, `.github <https://github.com/python/.github>`__. +* Documentation and websites for all the above: `python.org repository <https://github.com/python/pythondotorg>`__, `PEPs <https://github.com/python/peps>`__, `Devguide <https://github.com/python/devguide>`__, docs translations. +* Infrastructure for all the above: `docsbuild-scripts <https://github.com/python/docsbuild-scripts>`__, `buildmaster-config <https://github.com/python/buildmaster-config>`__. +* Discussions and notes around official development-related processes and events: `steering-council <https://github.com/python/steering-council>`__, `core-sprint <https://github.com/python/core-sprint>`__. Before adding a new repository to the organization, open a discussion to seek consensus -in the `Committers Discourse category <https://discuss.python.org/c/committers/5>`_. -Once people are satisfied with that, ask the `Python steering council <https://github.com/python/steering-council>`_ -to grant permission. +in the `Committers Discourse category <https://discuss.python.org/c/committers/5>`__. +Once people are satisfied with that, ask the `Python steering council <https://github.com/python/steering-council>`__ +to grant permission. Note that this process is not necessary for +:ref:`docs translations <translation-repo>` following +:pep:`PEP 545 <545#repository-for-po-files>`, which can be added at a +core team member’s discretion. Note that several repositories remain in the organization for historic reasons, and would probably not be appropriate to add today. @@ -244,18 +243,18 @@ and would probably not be appropriate to add today. Generally, new repositories should start their life under personal GitHub accounts or other GitHub orgs. It is relatively easy to move a repository to the organization once it is mature. For example, this would now apply to -experimental features like `asyncio <https://github.com/python/asyncio>`_, -`exceptiongroups <https://github.com/python/exceptiongroups>`_, +experimental features like `asyncio <https://github.com/python/asyncio>`__, +`exceptiongroups <https://github.com/python/exceptiongroups>`__, and drafts of new guides and other documentation (for example, `redistributor-guide -<https://github.com/python/redistributor-guide>`_). +<https://github.com/python/redistributor-guide>`__). -General-use tools and libraries (for example, `mypy <https://github.com/python/mypy>`_ -or `Black <https://github.com/psf/black>`_) should also be developed outside +General-use tools and libraries (for example, `mypy <https://github.com/python/mypy>`__ +or `Black <https://github.com/psf/black>`__) should also be developed outside the ``python`` organization, unless core devs (as represented by the SC) specifically want to “bless” one implementation (as with -`typeshed <https://github.com/python/typeshed>`_, -`tzdata <https://github.com/python/tzdata>`_, or -`pythoncapi-compat <https://github.com/python/pythoncapi-compat>`_). +`typeshed <https://github.com/python/typeshed>`__, +`tzdata <https://github.com/python/tzdata>`__, or +`pythoncapi-compat <https://github.com/python/pythoncapi-compat>`__). Organization owner policy @@ -267,13 +266,13 @@ at all levels including organization membership, team membership, access control, and merge privileges on all repositories. For full details of the permission levels see `GitHub's documentation on Organization permission levels -<https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles>`_. +<https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles>`__. This role is paramount to the security of the Python Language, Community, and Infrastructure. The Executive Director of the Python Software Foundation delegates authority on -GitHub Organization Owner Status to Ee Durbin - Python Software -Foundation Director of Infrastructure. Common reasons for this role are: +GitHub Organization Owner Status to Jacob Coffee - Python Software +Foundation Infrastructure Engineer. Common reasons for this role are: Infrastructure Staff Membership, Python Software Foundation General Counsel, and Python Software Foundation Staff as fallback. @@ -297,7 +296,7 @@ Current owners +----------------------+--------------------------------+-----------------+ | Donald Stufft | Infrastructure Staff | dstufft | +----------------------+--------------------------------+-----------------+ -| Ee Durbin | PSF Director of Infrastructure | ewdurbin | +| Ee Durbin | Infrastructure Staff | ewdurbin | +----------------------+--------------------------------+-----------------+ | Jacob Coffee | PSF Infrastructure Engineer | JacobCoffee | +----------------------+--------------------------------+-----------------+ @@ -318,13 +317,13 @@ The Administrator role on the repository allows for managing all aspects including collaborators, access control, integrations, webhooks, and branch protection. For full details of the permission levels see `GitHub's documentation on repository permission levels -<https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles>`_. -Common reasons for this role are: maintenance of Core Developer -Workflow tooling, Release Managers for all :ref:`in-development <indevbranch>`, +<https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles>`__. +Common reasons for this role are: maintenance of core +workflow tooling, Release Managers for all :ref:`in-development <indevbranch>`, :ref:`maintenance <maintbranch>`, and :ref:`security mode <secbranch>` -releases, and additional Python Core Developers as necessary for redundancy. -Occasional temporary administrator access is acceptable as necessary for Core -Developer workflow projects. +releases, and additional Python core team members as necessary for redundancy. +Occasional temporary administrator access is acceptable as necessary for core +workflow projects. Inactive or unreachable members may be removed with or without notice. Members who no longer necessitate this level of access will be removed with notice. @@ -335,27 +334,28 @@ Administrator of the repository. Current administrators ^^^^^^^^^^^^^^^^^^^^^^ -+-------------------+----------------------------------------------------------+-----------------+ -| Name | Role | GitHub Username | -+===================+==========================================================+=================+ -| Hugo van Kemenade | Python 3.14 and 3.15 Release Manager | hugovk | -+-------------------+----------------------------------------------------------+-----------------+ -| Thomas Wouters | Python 3.12 and 3.13 Release Manager | Yhg1s | -+-------------------+----------------------------------------------------------+-----------------+ -| Pablo Galindo | Python 3.10 and 3.11 Release Manager, | pablogsal | -| | Maintainer of buildbot.python.org | | -+-------------------+----------------------------------------------------------+-----------------+ -| Łukasz Langa | Python 3.9 Release Manager, | ambv | -| | PSF CPython Developer in Residence 2021-present | | -+-------------------+----------------------------------------------------------+-----------------+ -| Brett Cannon | | brettcannon | -+-------------------+----------------------------------------------------------+-----------------+ -| Ezio Melotti | Maintainer of bugs.python.org GitHub webhook integration | ezio-melotti | -+-------------------+----------------------------------------------------------+-----------------+ -| Mariatta Wijaya | Maintainer of bedevere, blurb_it and miss-islington | Mariatta | -+-------------------+----------------------------------------------------------+-----------------+ -| Seth Larson | PSF Security Developer-in-Residence | sethmlarson | -+-------------------+----------------------------------------------------------+-----------------+ ++--------------------+----------------------------------------------------------+-------------------+ +| Name | Role | GitHub Username | ++====================+==========================================================+===================+ +| Savannah Ostrowski | Python 3.16 and 3.17 Release Manager | savannahostrowski | ++--------------------+----------------------------------------------------------+-------------------+ +| Hugo van Kemenade | Python 3.14 and 3.15 Release Manager | hugovk | ++--------------------+----------------------------------------------------------+-------------------+ +| Thomas Wouters | Python 3.12 and 3.13 Release Manager | Yhg1s | ++--------------------+----------------------------------------------------------+-------------------+ +| Pablo Galindo | Python 3.10 and 3.11 Release Manager, | pablogsal | +| | Maintainer of buildbot.python.org | | ++--------------------+----------------------------------------------------------+-------------------+ +| Łukasz Langa | PSF CPython Developer in Residence 2021-present | ambv | ++--------------------+----------------------------------------------------------+-------------------+ +| Brett Cannon | | brettcannon | ++--------------------+----------------------------------------------------------+-------------------+ +| Ezio Melotti | Maintainer of bugs.python.org GitHub webhook integration | ezio-melotti | ++--------------------+----------------------------------------------------------+-------------------+ +| Mariatta Wijaya | Maintainer of bedevere, blurb_it and miss-islington | Mariatta | ++--------------------+----------------------------------------------------------+-------------------+ +| Seth Larson | PSF Security Developer-in-Residence | sethmlarson | ++--------------------+----------------------------------------------------------+-------------------+ Repository release manager role policy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/developer-workflow/extension-modules.rst b/developer-workflow/extension-modules.rst index 61c1ff08af..4d8c0ffca1 100644 --- a/developer-workflow/extension-modules.rst +++ b/developer-workflow/extension-modules.rst @@ -547,21 +547,24 @@ Now that the configuration is in place, it remains to compile the project: .. tip:: - Use ``make -j`` to speed-up compilation by utilizing as many CPU cores - as possible or ``make -jN`` to allow at most *N* concurrent jobs. + Use ``make -jN`` to speed-up compilation by utilizing as many CPU cores + as possible, where *N* is as many CPU cores you want to spare (and have + memory for). Be careful using ``make -j`` with no argument, as this puts + no limit on the number of jobs, and compilation can sometimes use up a + lot of memory (like when building with LTO). * ``make regen-configure`` updates the :cpy-file:`configure` script. - The :cpy-file:`configure` script must be generated using a specific version - of ``autoconf``. To that end, the :cpy-file:`Tools/build/regen-configure.sh` - script which the ``regen-configure`` rule is based on either requires Docker - or Podman, the latter being assumed by default. + The :cpy-file:`configure` script must be generated using a specific version + of ``autoconf``. To that end, the :cpy-file:`Tools/build/regen-configure.sh` + script which the ``regen-configure`` rule is based on either requires Docker + or Podman, the latter being assumed by default. - .. tip:: + .. tip:: - We recommend installing `Podman <https://podman.io/docs/installation>`_ - instead of Docker since the former does not require a background service - and avoids creating files owned by the ``root`` user in some cases. + We recommend installing `Podman <https://podman.io/docs/installation>`__ + instead of Docker since the former does not require a background service + and avoids creating files owned by the ``root`` user in some cases. * ``make regen-all`` is responsible for regenerating header files and invoking other scripts, such as :ref:`Argument Clinic <clinic>`. @@ -571,7 +574,7 @@ Now that the configuration is in place, it remains to compile the project: :mod:`!_foo` discoverable and importable via ``import _foo``. * The final ``make`` step is generally not needed since the previous ``make`` - invokations may completely rebuild the project, but it could be needed in + invocations may completely rebuild the project, but it could be needed in some specific cases. Troubleshooting @@ -606,8 +609,8 @@ by executing :cpy-file:`Tools/build/regen-configure.sh`: If Docker complains about missing permissions, this Stack Overflow post could be useful in solving the issue: `How to fix docker: permission denied -<https://stackoverflow.com/q/48957195/9579194>`_. Alternatively, you may try -using `Podman <https://podman.io/docs/installation>`_. +<https://stackoverflow.com/q/48957195/9579194>`__. Alternatively, you may try +using `Podman <https://podman.io/docs/installation>`__. Missing ``Py_BUILD_CORE`` define when using internal headers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/developer-workflow/grammar.rst b/developer-workflow/grammar.rst index d574dfed7d..bd314c61e3 100644 --- a/developer-workflow/grammar.rst +++ b/developer-workflow/grammar.rst @@ -5,4 +5,4 @@ Changing CPython's grammar ========================== This document is now part of the -`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/changing_grammar.md>`_. +`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/changing_grammar.md>`__. diff --git a/developer-workflow/index.rst b/developer-workflow/index.rst index e73927f1dd..9919398e62 100644 --- a/developer-workflow/index.rst +++ b/developer-workflow/index.rst @@ -8,11 +8,11 @@ Development workflow :maxdepth: 5 communication-channels + lang-changes development-cycle stdlib extension-modules c-api - lang-changes grammar porting sbom diff --git a/developer-workflow/lang-changes.rst b/developer-workflow/lang-changes.rst index 52aabb15dd..0b2c613fa7 100644 --- a/developer-workflow/lang-changes.rst +++ b/developer-workflow/lang-changes.rst @@ -1,37 +1,43 @@ .. _lang-changes: .. _langchanges: -Changing the Python language -============================ -On occasion people come up with an idea on how to change or improve Python as a -programming language. This document is meant to explain exactly what changes -have a reasonable chance of being considered and what the process is to propose -changes to the language. +Changing Python +=============== +On occasion people come up with an idea for changing or improving the Python +language or standard library. +This page explains how to propose changes and what to expect during the +process. -What qualifies + +Considerations -------------- -First and foremost, it must be understood that changes to the Python -programming language are difficult to make. When the language changes, -**every** Python programmer already in existence and all Python programmers to + +First, understand that changes to Python +are difficult to make. When the language changes, +**every** Python programmer and all Python programmers to come will end up eventually learning about the change you want to propose. Books will need updating, code will be changed, and a new way to do things will -need to be learned. Changes to the Python programming language are never taken +need to be learned. Changes to Python are never taken lightly. -Because of the seriousness that language changes carry, any change must be -beneficial to a large proportion of Python users. If the change only benefits a -small percentage of Python developers then the change will not be made. A good -way to see if your idea would work for a large portion of the Python community -is to ask in the `Ideas Discourse category`_. You can also -go through Python's stdlib and find examples of code which would benefit from -your proposed change (which helps communicate the usefulness of your change to -others). For further guidance, see :ref:`suggesting-changes`. +Backward compatibility is a significant concern. Existing Python code has to +continue to work. There are exceptions to this rule, but they are very rare +and are only allowed when the benefits of the change greatly outweigh the costs +of breaking existing code. -Your proposed change also needs to be *Pythonic*. While only the Steering -Council can truly classify something as Pythonic, you can read the -:pep:`Zen of Python <20>` for guidance. +Because of the seriousness of changing the language, any change must be +beneficial to many Python users. If the change only helps a small percentage of +Python developers then the change will not be made. A good way to see if your +idea would work for a large portion of the Python community is to discuss it in +the `Ideas category in Discourse <ideas_>`_. You can also look in Python's standard +library to find examples of code which would benefit from your proposed change. +.. important:: + For all of these reasons, most proposed changes to Python are rejected. This + doesn't mean you shouldn't suggest them. It can be useful to explore + alternatives and to get feedback from the community. Just be aware that + getting a change accepted is difficult. Don't take it personally. .. index:: single: PEP process @@ -41,25 +47,107 @@ Council can truly classify something as Pythonic, you can read the Suggesting new features and language changes -------------------------------------------- -The `Ideas Discourse category`_ -is specifically intended for discussion of new features and language changes. -Please don't be disappointed if your idea isn't met with universal approval: -as the :pep:`long list of Withdrawn and Rejected PEPs -<0#rejected-superseded-and-withdrawn-peps>` -in the :pep:`PEP Index <0>` attests, -and as befits a reasonably mature programming language, -getting significant changes into Python isn't a simple task. +Proposing a change involves the following steps: + +- Describe your idea in detail. + +- Engage in discussion about the idea. + +- Rarely, the idea will advance to a formal proposal stage. + + +Describe your idea +^^^^^^^^^^^^^^^^^^ + +The `Ideas category in Discourse <ideas_>`_ is specifically intended for discussion +of new features and language changes. Make your proposal as a `new topic +<ideas_>`_ there. + +Your proposal needs to be **detailed**. Describe the change you want to make, +why you want to make it, and what benefits it will bring to Python users. Be +specific. Show that you have considered the effect of the change on existing +code. + +Some things you should **not** do: + +- **Don't** format your idea as a Python Enhancement Proposal (PEP). + It's good to use the PEP template as a guide for what information to include, + but don't try to write a full PEP until the idea has been accepted for + further consideration. + +- **Don't** create a list of proposed changes. Each idea needs its own + discussion. Proposing a change is significant work. You will need to spend + time on each proposal. A tossed-off list will not be taken seriously. + +When justifying your idea, these are **not good reasons** to make a change: + +- "Other languages work this way." Languages are different. What works well + in one language may not work well in Python, or Python may already have a + way to do a similar thing. + +- "It would be nice." This is too vague. Be specific about the benefits + your change will bring, and consider the costs as well. + +Some things you **should** do: + +- Research whether your idea has been proposed before. There are many + suggestions that have been made and rejected in the past. If your idea has a + history, read the discussion to see why it was rejected. Previously rejected + ideas are especially unlikely to get accepted. If you can address the + concerns raised in the previous discussion, mention that in your proposal. + +- Read other ideas to see how they are presented. This will help you flesh out + your proposal. + +- Read other ideas to understand the kinds of concerns that are raised and + objections that must be answered. Your proposal will be stronger if you can + address these concerns up front. + +- Provide enough detail to fully explain your idea, and to show that you have + considered all the implications of the change. Strike the right balance + between brevity and completeness. A shorter proposal will be easier to + discuss, so long as it includes all the necessary information. + + +Engage in discussion +^^^^^^^^^^^^^^^^^^^^ + +Once you post your proposal, people will respond. You need to continue +the discussion, answer questions, and address objections. This is an important +part of the process. Other people's perspectives will help explore the full +impact of the idea and find strengths or weaknesses you may not have +considered. + +You will almost always get at least some push-back. Don't be disappointed, +and don't take it personally. +As the long list of :pep:`Withdrawn and Rejected PEPs +<0#rejected-superseded-and-withdrawn-peps>` in the :pep:`PEP Index <0>` +attests, and as befits a mature programming language, getting significant +changes into Python isn't a simple task. + +Engage in good faith. The goal of the discussion is to find the best balance +between competing concerns. If your idea has merit, the discussion will help +refine it and make it stronger. If your idea has flaws, the discussion will +help identify them so you can address them or move on. Keep the discussion +productive and focused on the issues, not on personalities. + +It is especially useful to discuss with core team members since +they know the language and design considerations well. +If your proposal makes it to the PEP stage, +you'll need a core team member as a sponsor. +Sometimes they will differ in opinion, or merely be unconvinced. When there +isn't a clear positive sentiment, the `Status Quo Wins a Stalemate`_. + +Even if your idea is not accepted, the discussion can help you and others +understand the design of Python better, and help inform future proposals. -If the idea is reasonable, someone will suggest posting it as a feature -request on the `issue tracker`_, or, for larger changes, -writing it up as PEP following the :ref:`lang-changes-pep-process`. -Sometimes core developers will differ in opinion, -or merely be collectively unconvinced. -When there isn't an obvious victor, then the `Status Quo Wins a Stalemate`_. +Formal proposal +^^^^^^^^^^^^^^^ -For some examples on language changes that were accepted, -see `Justifying Python Language Changes`_. +If the idea gets positive discussion, someone will suggest posting it as a +feature request on the `issue tracker`_, or, for larger changes, writing it up +as PEP following the :ref:`lang-changes-pep-process`. Congratulations! .. index:: PEP process @@ -69,20 +157,20 @@ see `Justifying Python Language Changes`_. PEP process ----------- -Once you are certain you have a language change proposal -which will appeal to the general Python community, -you can begin the :abbr:`PEP (Python enhancement proposal)` process -to officially propose the change. -See :pep:`1` for information on PEPs and the PEP process, -and the :pep:`PEP Index <0>` for examples. +Once you have a proposal which will appeal to +the general Python community, you can begin the PEP +process to officially propose the change. +This starts with finding a sponsor from the core team. +See :pep:`1` for +information on PEPs and the PEP process, and the :pep:`PEP Index <0>` for +examples. -If the PEP is accepted, then your proposed language change will be introduced -in the next release of Python. -Otherwise, your PEP will be recorded as rejected along with an explanation, -to inform others who may propose a similar language change in the future. +If the PEP is accepted, then your language change will be introduced in a +future release of Python. Otherwise, your PEP will be recorded as rejected +along with an explanation, to inform others who may propose a similar language +change in the future. .. _issue tracker: https://github.com/python/cpython/issues -.. _Ideas Discourse category: https://discuss.python.org/c/ideas/6 -.. _Status Quo Wins a Stalemate: https://www.curiousefficiency.org/posts/2011/02/status-quo-wins-stalemate.html -.. _Justifying Python Language Changes: https://www.curiousefficiency.org/posts/2011/02/justifying-python-language-changes.html +.. _ideas: https://discuss.python.org/c/ideas/6 +.. _Status Quo Wins a Stalemate: https://www.curiousefficiency.org/posts/2011/02/status-quo-wins-stalemate/ diff --git a/developer-workflow/psrt-emeritus.csv b/developer-workflow/psrt-emeritus.csv new file mode 100644 index 0000000000..f9d26bfba4 --- /dev/null +++ b/developer-workflow/psrt-emeritus.csv @@ -0,0 +1,10 @@ +Anthony Baxter,,Release Manager +Christian Heimes,tiran, +Georg Brandl,birkenfeld, +Huzaifa Sidhpurwala,, +Jesse Noller,, +Kushal Das,kushaldas, +Mark Hammond,mhammond, +Nam Nguyen,, +Neal Norwitz,, +Trent Mick,, diff --git a/developer-workflow/psrt.csv b/developer-workflow/psrt.csv new file mode 100644 index 0000000000..81147eb29e --- /dev/null +++ b/developer-workflow/psrt.csv @@ -0,0 +1,25 @@ +Barry Warsaw,warsaw,Admin +Benjamin Peterson,benjaminp, +Donald Stufft,dstufft, +Dustin Ingram,di, +Ee Durbin,ewdurbin,Admin +Emma Smith,emmatyping, +Glyph Lefkowitz,glyph, +Gregory P. Smith,gpshead, +Hugo van Kemenade,hugovk,Release Manager +Jacob Coffee,JacobCoffee, +Larry Hastings,larryhastings, +Łukasz Langa,ambv,Release Manager +Ned Deily,ned-deily,"Admin, Release Manager" +Pablo Galindo Salgado,pablogsal,Release Manager +Paul McMillan,paulmcmillan, +Petr Viktorin,encukou, +Pradyun Gedam,pradyunsg, +Savannah Ostrowski,savannahostrowski,Release Manager +Serhiy Storchaka,serhiy-storchaka, +Seth Larson,sethmlarson,Admin +Stan Ulbrych,StanFromIreland, +Steve Dower,zooba,Release Manager +Thomas Wouters,Yhg1s,Release Manager +Tim Peters,tim-one, +William Woodruff,woodruffw, diff --git a/developer-workflow/psrt.rst b/developer-workflow/psrt.rst index f469f68d12..dee901726e 100644 --- a/developer-workflow/psrt.rst +++ b/developer-workflow/psrt.rst @@ -4,6 +4,84 @@ Python Security Response Team (PSRT) The Python Security Response Team (PSRT) is responsible for handling vulnerability reports for CPython and pip. +Members +------- + +The PSRT publishes a full +list of members and admins, included in the table below: + +.. csv-table:: + :header: "Name", "GitHub username", "Notes" + :file: psrt.csv + :encoding: "utf-8" + +See also the :ref:`members emeritus list <psrt-members-emeritus>`. + +How can I join the PSRT? +~~~~~~~~~~~~~~~~~~~~~~~~ + +Anyone can join the PSRT following a nomination process +`similar to core team nominations`_. Nomination for a new member +is brought to the PSRT by an existing PSRT member and then +this nomination is voted on by existing PSRT members. +The nomination succeeds if the nomination receives at least +two-thirds positive votes from a vote of existing PSRT members +that is open for one week and not vetoed by the Steering Council. + +Once per year the Steering Council will receive a report of inactive members +of the PSRT with the recommendation to remove the inactive users from the PSRT. +“Inactive” is defined as a member who hasn’t coordinated or commented on a +vulnerability report in the past year since the last report was generated. +The Steering Council may remove members of the PSRT with a simple vote. + +Members of the PSRT who are a Release Manager or Steering Council member may +remain in the PSRT regardless of inactivity in vulnerability reports. + +.. _similar to core team nominations: https://devguide.python.org/core-team/join-team/ + +Responsibilities of PSRT members +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Below are the responsibilities of PSRT members: + +* Being knowledgeable about typical software vulnerability report handling + processes, such as CVE IDs, patches, coordinated disclosure, embargoes. +* Not sharing or acting on embargoed information about the reported + vulnerability. Examples of disallowed behavior include sharing information + with colleagues or publicly deploying unpublished mitigations or patches ahead + of the advisory publication date. +* Acting as a “Coordinator” of vulnerability reports that are submitted to + projects. A Coordinator’s responsibility is to move a report through the PSRT + process to a “finished” state, either rejected or as a published advisory and + mitigation, within the industry standard timeline of 90 days. +* As a Coordinator, involving relevant core team members or triagers where + necessary to make a determination whether a report is a vulnerability and + developing a patch. Coordinators are encouraged to involve members of the core + team to make the best decision for each report rather than working in isolation. +* As a Coordinator, calculating the severity using CVSS and authoring advisories + to be shared on `security-announce@python.org`_. These advisories are used for + CVE records by the `PSF CVE Numbering Authority`_. +* Coordinators that can no longer move a report forwards for any reason must + delegate their Coordinator role to someone else in the PSRT. + +.. _security-announce@python.org: https://mail.python.org/archives/list/security-announce@python.org/ +.. _PSF CVE Numbering Authority: https://www.python.org/cve-numbering-authority/ + +Responsibilities of PSRT admins +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +PSRT members who are designated as admins by the Steering Council have the +following additional responsibilities: + +* Triaging the ``security@python.org`` mailing list. +* Managing PSRT membership access including the GitHub team, the mailing list, + and Discord channel, to ensure they are synchronized with the canonical list + of PSRT members. +* On a yearly basis, providing the Steering Council with a report including a + list of inactive PSRT members. +* Running nomination elections, including counting final votes and giving + the Steering Council an opportunity to veto nominations via email. + Vulnerability report triage --------------------------- @@ -31,7 +109,7 @@ If a coordinator can't complete the process for any reason (time obligation, vacation, etc.) they must find a replacement coordinator in the PSRT and reassign the vulnerability report appropriately. -Coordinators are expected to collaborate with other PSRT members and core developers +Coordinators are expected to collaborate with other PSRT and core team members when needed for guidance on whether the report is an actual vulnerability, severity, advisory text, and fixes. @@ -74,7 +152,7 @@ severity, advisory text, and fixes. * The coordinator determines the fix approach and who will provide a fix. Some reporters are willing to provide or collaborate to create a fix, - otherwise relevant core developers can be invited to collaborate by + otherwise relevant core team members can be invited to collaborate by the coordinator. * For **Low** and **Medium** severity vulnerabilities it is acceptable @@ -84,7 +162,7 @@ severity, advisory text, and fixes. * For **High** and **Critical** severity vulnerabilities the fix must be developed privately using GitHub Security Advisories' "Private Forks" feature. - Core developers can be added to the GitHub Security Advisory via "collaborators" + Core team members can be added to the GitHub Security Advisory via "collaborators" to work on the fix together. Once a fix is approved privately and tested, a public issue and pull request can be created with the ``security`` and ``release-blocker`` labels. @@ -93,6 +171,40 @@ severity, advisory text, and fixes. to ``security-announce@python.org`` using the below template. Backport labels must be added as appropriate. After the advisory is published a CVE record can be created. +Handling code signing certificate reports +----------------------------------------- + +Python signs binaries using Azure Trusted Signing and Apple Developer ID +certificates. If a code signing certificate is reported as "compromised" or +"malware signed with certificate", the Python Security Response Team must +request the following information from the reporter: + +* Checksum(s) of binaries signed by certificate. +* Signature(s) of binaries signed by certificate. + +To avoid unnecessary user confusion and churn around revoking code signing +certificates, any reports **must be verifiable independently by the PSRT before +taking destructive actions**, such as revoking certificates. With this +information the PSRT can take investigative steps to verify the report, such as: + +* Downloading and checking artifacts from the associated Azure Pipelines + executions against the reported list of checksums. +* Verifying the validity of the signatures. `Past reports + <https://discuss.python.org/t/103356/2>`__ have contained signatures that + purported to be from Python code signing certificates, but were not valid. +* Checking the Azure Pipelines and Azure Trusted Signing audit logs for signs of + compromise. + +If any signs of compromise or incorrectly signed binaries are discovered by the +PSRT, only then will certificates be revoked and an advisory published. +If compromise is reported, the following non-destructive actions can be taken by +the PSRT without verifying the reported information as a precaution, if +relevant: + +* Rotating secrets associated with code signing (``TrustedSigningSecret`` for + Azure Trusted Publishing). +* Resetting passwords for accounts with access to signing certificates. + Template responses ------------------ @@ -158,3 +270,15 @@ please feel free to adapt them as needed for the current context. * https://www.cve.org/CVERecord?id={CVE-YYYY-XXXX} * {pull request URL} + +.. _psrt-members-emeritus: + +Members emeritus +---------------- + +Members who have previously served on the PSRT. + +.. csv-table:: + :header: "Name", "GitHub username", "Notes" + :file: psrt-emeritus.csv + :encoding: "utf-8" diff --git a/developer-workflow/sbom.rst b/developer-workflow/sbom.rst index 756c175708..c8a2facd14 100644 --- a/developer-workflow/sbom.rst +++ b/developer-workflow/sbom.rst @@ -5,15 +5,15 @@ Software Bill-of-Materials (abbreviated as "SBOM") is a document for sharing information about software and how it's been composed. This format is used most often in the security space for checking software and its dependencies for vulnerabilities using vulnerability databases like -`CVE <https://www.cve.org/>`_ and `OSV <https://osv.dev/>`_. The SBOM format -that the CPython project uses is `SPDX <https://spdx.github.io/spdx-spec/v2.3/>`_ +`CVE <https://www.cve.org/>`__ and `OSV <https://osv.dev/>`__. The SBOM format +that the CPython project uses is `SPDX <https://spdx.github.io/spdx-spec/v2.3/>`__ which can be transformed into other formats if necessary by consumers. There are multiple sources of third-party dependencies for CPython. Some are vendored into the source code of CPython itself (like ``mpdecimal`` vendored at :cpy-file:`Modules/_decimal/libmpdec`) or they could be optionally pulled in during builds like Windows using dependencies from the -`python/cpython-source-deps <https://github.com/python/cpython-source-deps>`_ +`python/cpython-source-deps <https://github.com/python/cpython-source-deps>`__ repository. Whenever adding or updating a third-party dependency, an update will likely @@ -51,10 +51,10 @@ Adding a new dependency When adding a dependency it's important to have the following information: * Name, version, and download URL of the project -* License of the project as an `SPDX License Expression <https://spdx.org/licenses/>`_ +* License of the project as an `SPDX License Expression <https://spdx.org/licenses/>`__ * Software identifiers that match values in vulnerability databases - (`CPE <https://nvd.nist.gov/products/cpe>`_ and - `Package URLs <https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst>`_ + (`CPE <https://nvd.nist.gov/products/cpe>`__ and + `Package URLs <https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst>`__ or "PURLs") * Paths to include and exclude in the CPython source tree corresponding to this dependency diff --git a/developer-workflow/stdlib.rst b/developer-workflow/stdlib.rst index 60112d6d3e..b683e55e96 100644 --- a/developer-workflow/stdlib.rst +++ b/developer-workflow/stdlib.rst @@ -28,7 +28,7 @@ You have a several options for this: * Search the `issue tracker`_ for discussion related to the proposed addition. This may turn up an issue that explains why the suggestion wasn't accepted. * Open a new thread in the `Ideas Discourse category`_ - to gather feedback directly from the Python core developers and community. + to gather feedback directly from the Python core team and community. * Write a blog post about the code, which may also help gather useful feedback. If you have found general acceptance and usefulness for your code from people, @@ -36,9 +36,9 @@ you can open an issue on the `issue tracker`_ with the code attached as a :ref:`pull request <pullrequest>`. If possible, also submit a :ref:`contributor agreement <contributor_agreement>`. -If a core developer decides that your code would be useful to the general +If a core team member decides that your code would be useful to the general Python community, they will then commit your code. If your code is not picked -up by a core developer and committed then please do not take this personally. +up by a core team and committed then please do not take this personally. Through your public sharing of your code in order to gauge community support for it you at least can know that others will come across it who may find it useful. @@ -51,8 +51,8 @@ Adding a new module It must be stated upfront that getting a new module into the stdlib is very difficult. Adding any significant amount of code to the stdlib increases the -burden placed upon core developers. It also means that the module somewhat -becomes "sanctioned" by the core developers as a good way to do something, +burden placed upon the core team. It also means that the module somewhat +becomes "sanctioned" by the core team as a good way to do something, typically leading to the rest of the Python community to using the new module over other available solutions. All of this means that additions to the stdlib are not taken lightly. @@ -76,7 +76,7 @@ that the stdlib consists of. While a new stdlib module does not need to appeal to all users of Python, it should be something that a large portion of the community will find useful. -This makes sure that the developer burden placed upon core developers is worth +This makes sure that the developer burden placed upon the core team is worth it. @@ -108,12 +108,12 @@ infrastructure (that is, the module is no longer directly maintained outside of Python). This prevents a divergence between the code that is included in the stdlib and that which is released outside the stdlib (typically done to provide the module to older versions of Python). It also removes the burden of forcing -core developers to have to redirect bug reports or changes to an external issue +the core team to have to redirect bug reports or changes to an external issue tracker and :abbr:`VCS (version control system)`. Someone involved with the development of the module must promise to help maintain the module in the stdlib for two years. -This not only helps out other core developers by alleviating workload from bug +This not only helps out other core team members by alleviating workload from bug reports that arrive from the first Python release containing the module, but also helps to make sure that the overall design of the module continues to be uniform. diff --git a/development-tools/clang.rst b/development-tools/clang.rst index f06834731a..149fb7adcf 100644 --- a/development-tools/clang.rst +++ b/development-tools/clang.rst @@ -11,7 +11,7 @@ libraries. This document does not cover interpreting the findings. For a discussion of interpreting results, see Marshall Clow's `Testing libc++ with --fsanitize=undefined <https://cplusplusmusings.wordpress.com/tag/clang/>`_. The +-fsanitize=undefined <https://cplusplusmusings.wordpress.com/tag/clang/>`__. The blog posting is a detailed examinations of issues uncovered by Clang in ``libc++``. @@ -45,7 +45,7 @@ flags are passed through ``CFLAGS`` and ``CXXFLAGS``, and sometimes through ``CC`` and ``CXX`` (in addition to the compiler). A complete list of sanitizers can be found at `Controlling Code Generation -<https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation>`_. +<https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation>`__. .. note:: @@ -70,7 +70,7 @@ Pre-built Clang builds are available for most platforms: includes the "C++ clang tools for windows" feature. You can also build ``clang`` from source; refer to -`the clang documentation <https://clang.llvm.org/>`_ for details. +`the clang documentation <https://clang.llvm.org/>`__ for details. The installer does not install all the components needed on occasion. For example, you might want to run a ``scan-build`` or examine the results with @@ -103,6 +103,10 @@ Then, run ``./configure`` with the relevant flags: * ASan: ``--with-address-sanitizer --without-pymalloc`` * UBsan: ``--with-undefined-behavior-sanitizer`` +The ``--without-pymalloc`` option is not necessary (tests should pass without it), +but disabling pymalloc helps ASan uncover more bugs (ASan does not track +individual allocations done by pymalloc). + It is OK to specify both sanitizers. After that, run ``make`` and ``make test`` as usual. @@ -280,6 +284,6 @@ Or, you could ignore the entire file with:: Unfortunately, you won't know what to ignorelist until you run the sanitizer. The documentation is available at `Sanitizer special case list -<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. +<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`__. .. _Valgrind: https://github.com/python/cpython/blob/main/Misc/README.valgrind diff --git a/development-tools/clinic.rst b/development-tools/clinic/howto.rst similarity index 71% rename from development-tools/clinic.rst rename to development-tools/clinic/howto.rst index 642f40dce9..359c53e903 100644 --- a/development-tools/clinic.rst +++ b/development-tools/clinic/howto.rst @@ -1,677 +1,3 @@ -.. highlight:: c - -.. _clinic: - -*************** -Argument Clinic -*************** - -:author: Larry Hastings - -**Source code:** :cpy-file:`Tools/clinic/clinic.py`. - -Argument Clinic is a preprocessor for CPython C files. -It was introduced in Python 3.4 with :pep:`436`, -in order to provide introspection signatures, -and to generate performant and tailor-made boilerplate code -for argument parsing in CPython builtins, module level functions, and class methods. -This document is divided in four major sections: - -* :ref:`clinic-background` talks about the basic concepts and goals of Argument Clinic. -* :ref:`clinic-reference` describes the command-line interface and Argument Clinic terminology. -* :ref:`clinic-tutorial` guides you through all the steps required to adapt an existing C function to Argument Clinic. -* :ref:`clinic-howtos` details how to handle specific tasks. - - -.. note:: - - Argument Clinic is considered internal-only - for CPython. Its use is not supported for files outside - CPython, and no guarantees are made regarding backwards - compatibility for future versions. In other words: if you - maintain an external C extension for CPython, you're welcome - to experiment with Argument Clinic in your own code. But the - version of Argument Clinic that ships with the next version - of CPython *could* be totally incompatible and break all your code. - - -.. _clinic-background: - -Background -========== - -Basic concepts --------------- - -When Argument Clinic is run on a file, either via the :ref:`clinic-cli` -or via ``make clinic``, it will scan over the input files looking for -:term:`start lines <start line>`: - -.. code-block:: none - - /*[clinic input] - -When it finds one, it reads everything up to the :term:`end line`: - -.. code-block:: none - - [clinic start generated code]*/ - -Everything in between these two lines is Argument Clinic :term:`input`. -When Argument Clinic parses input, it generates :term:`output`. -The output is rewritten into the C file immediately after the input, -followed by a :term:`checksum line`. -All of these lines, including the :term:`start line` and :term:`checksum line`, -are collectively called an Argument Clinic :term:`block`: - -.. code-block:: none - - /*[clinic input] - ... clinic input goes here ... - [clinic start generated code]*/ - ... clinic output goes here ... - /*[clinic end generated code: ...]*/ - -If you run Argument Clinic on the same file a second time, Argument Clinic -will discard the old :term:`output` and write out the new output with a fresh -:term:`checksum line`. -If the :term:`input` hasn't changed, the output won't change either. - -.. note:: - - You should never modify the output of an Argument Clinic block, - as any change will be lost in future Argument Clinic runs; - Argument Clinic will detect an output checksum mismatch and regenerate the - correct output. - If you are not happy with the generated output, - you should instead change the input until it produces the output you want. - - -.. _clinic-reference: - -Reference -========= - - -.. _clinic-terminology: - -Terminology ------------ - -.. glossary:: - - start line - The line ``/*[clinic input]``. - This line marks the beginning of Argument Clinic input. - Note that the *start line* opens a C block comment. - - end line - The line ``[clinic start generated code]*/``. - The *end line* marks the _end_ of Argument Clinic :term:`input`, - but at the same time marks the _start_ of Argument Clinic :term:`output`, - thus the text *"clinic start start generated code"* - Note that the *end line* closes the C block comment opened - by the *start line*. - - checksum - A hash to distinguish unique :term:`inputs <input>` - and :term:`outputs <output>`. - - checksum line - A line that looks like ``/*[clinic end generated code: ...]*/``. - The three dots will be replaced by a :term:`checksum` generated from the - :term:`input`, and a :term:`checksum` generated from the :term:`output`. - The checksum line marks the end of Argument Clinic generated code, - and is used by Argument Clinic to determine if it needs to regenerate - output. - - input - The text between the :term:`start line` and the :term:`end line`. - Note that the start and end lines open and close a C block comment; - the *input* is thus a part of that same C block comment. - - output - The text between the :term:`end line` and the :term:`checksum line`. - - block - All text from the :term:`start line` to the :term:`checksum line` inclusively. - - -.. _clinic-cli: - -Command-line interface ----------------------- - -The Argument Clinic :abbr:`CLI (Command-Line Interface)` is typically used to -process a single source file, like this: - -.. code-block:: shell-session - - $ python3 ./Tools/clinic/clinic.py foo.c - -The CLI supports the following options: - -.. program:: ./Tools/clinic/clinic.py [-h] [-f] [-o OUTPUT] [-v] \ - [--converters] [--make] [--srcdir SRCDIR] [--limited] [FILE ...] - -.. option:: -h, --help - - Print CLI usage. - -.. option:: -f, --force - - Force output regeneration. - -.. option:: -o, --output OUTPUT - - Redirect file output to OUTPUT - -.. option:: -v, --verbose - - Enable verbose mode. - -.. option:: --converters - - Print a list of all supported converters and return converters. - -.. option:: --make - - Walk :option:`--srcdir` to run over all relevant files. - -.. option:: --srcdir SRCDIR - - The directory tree to walk in :option:`--make` mode. - -.. option:: --exclude EXCLUDE - - A file to exclude in :option:`--make` mode. - This option can be given multiple times. - -.. option:: --limited - - Use the :ref:`Limited API <limited-c-api>` to parse arguments in the generated C code. - See :ref:`clinic-howto-limited-capi`. - -.. option:: FILE ... - - The list of files to process. - - -.. _clinic-classes: - -Classes for extending Argument Clinic -------------------------------------- - -.. module:: clinic - -.. class:: CConverter - - The base class for all converters. - See :ref:`clinic-howto-custom-converter` for how to subclass this class. - - .. attribute:: type - - The C type to use for this variable. - :attr:`!type` should be a Python string specifying the type, - for example, ``'int'``. - If this is a pointer type, the type string should end with ``' *'``. - - .. attribute:: default - - The Python default value for this parameter, as a Python value. - Or the magic value ``unspecified`` if there is no default. - - .. attribute:: py_default - - :attr:`!default` as it should appear in Python code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_default - - :attr:`!default` as it should appear in C code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_ignored_default - - The default value used to initialize the C variable when - there is no default, but not specifying a default may - result in an "uninitialized variable" warning. This can - easily happen when using option groups—although - properly written code will never actually use this value, - the variable does get passed in to the impl, and the - C compiler will complain about the "use" of the - uninitialized value. This value should always be a - non-empty string. - - .. attribute:: converter - - The name of the C converter function, as a string. - - .. attribute:: impl_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into the impl function. - - .. attribute:: parse_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into :c:func:`PyArg_ParseTuple`. - - -.. _clinic-tutorial: - -Tutorial -======== - -The best way to get a sense of how Argument Clinic works is to -convert a function to work with it. Here, then, are the bare -minimum steps you'd need to follow to convert a function to -work with Argument Clinic. Note that for code you plan to -check in to CPython, you really should take the conversion farther, -using some of the :ref:`advanced concepts <clinic-howtos>` -you'll see later on in the document, -like :ref:`clinic-howto-return-converters` -and :ref:`clinic-howto-self-converter`. -But we'll keep it simple for this walkthrough so you can learn. - -First, make sure you're working with a freshly updated checkout -of the CPython trunk. - -Next, find a Python builtin that calls either :c:func:`PyArg_ParseTuple` -or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted -to work with Argument Clinic yet. -For this tutorial, we'll be using -:py:meth:`_pickle.Pickler.dump <pickle.Pickler.dump>`. - -If the call to the :c:func:`!PyArg_Parse*` function uses any of the -following format units...: - -.. code-block:: none - - O& - O! - es - es# - et - et# - -... or if it has multiple calls to :c:func:`PyArg_ParseTuple`, -you should choose a different function. -(See :ref:`clinic-howto-advanced-converters` for those scenarios.) - -Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` -or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different -types for the same argument, or if the function uses something besides -:c:func:`!PyArg_Parse*` functions to parse its arguments, it probably -isn't suitable for conversion to Argument Clinic. Argument Clinic -doesn't support generic functions or polymorphic parameters. - -Next, add the following boilerplate above the function, -creating our input block:: - - /*[clinic input] - [clinic start generated code]*/ - -Cut the docstring and paste it in between the ``[clinic]`` lines, -removing all the junk that makes it a properly quoted C string. -When you're done you should have just the text, based at the left -margin, with no line wider than 80 characters. -Argument Clinic will preserve indents inside the docstring. - -If the old docstring had a first line that looked like a function -signature, throw that line away; The docstring doesn't need it anymore --- -when you use :py:func:`help` on your builtin in the future, -the first line will be built automatically based on the function's signature. - -Example docstring summary line:: - - /*[clinic input] - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If your docstring doesn't have a "summary" line, Argument Clinic will -complain, so let's make sure it has one. The "summary" line should -be a paragraph consisting of a single 80-column line -at the beginning of the docstring. -(See :pep:`257` regarding docstring conventions.) - -Our example docstring consists solely of a summary line, so the sample -code doesn't have to change for this step. - -Now, above the docstring, enter the name of the function, followed -by a blank line. This should be the Python name of the function, -and should be the full dotted path to the function --- -it should start with the name of the module, -include any sub-modules, and if the function is a method on -a class it should include the class name too. - -In our example, :mod:`!_pickle` is the module, :py:class:`!Pickler` is the class, -and :py:meth:`!dump` is the method, so the name becomes -:py:meth:`!_pickle.Pickler.dump`:: - - /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If this is the first time that module or class has been used with Argument -Clinic in this C file, -you must declare the module and/or class. Proper Argument Clinic hygiene -prefers declaring these in a separate block somewhere near the -top of the C file, in the same way that include files and statics go at -the top. -In our sample code we'll just show the two blocks next to each other. - -The name of the class and module should be the same as the one -seen by Python. Check the name defined in the :c:type:`PyModuleDef` -or :c:type:`PyTypeObject` as appropriate. - -When you declare a class, you must also specify two aspects of its type -in C: the type declaration you'd use for a pointer to an instance of -this class, and a pointer to the :c:type:`!PyTypeObject` for this class:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -Declare each of the parameters to the function. Each parameter -should get its own line. All the parameter lines should be -indented from the function name and the docstring. -The general form of these parameter lines is as follows: - -.. code-block:: none - - name_of_parameter: converter - -If the parameter has a default value, add that after the -converter: - -.. code-block:: none - - name_of_parameter: converter = default_value - -Argument Clinic's support for "default values" is quite sophisticated; -see :ref:`clinic-howto-default-values` for more information. - -Next, add a blank line below the parameters. - -What's a "converter"? -It establishes both the type of the variable used in C, -and the method to convert the Python value into a C value at runtime. -For now you're going to use what's called a "legacy converter" --- -a convenience syntax intended to make porting old code into Argument -Clinic easier. - -For each parameter, copy the "format unit" for that -parameter from the :c:func:`PyArg_Parse` format argument and -specify *that* as its converter, as a quoted string. -The "format unit" is the formal name for the one-to-three -character substring of the *format* parameter that tells -the argument parsing function what the type of the variable -is and how to convert it. -For more on format units please see :ref:`arg-parsing`. - -For multicharacter format units like ``z#``, -use the entire two-or-three character string. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If your function has ``|`` in the format string, -meaning some parameters have default values, you can ignore it. -Argument Clinic infers which parameters are optional -based on whether or not they have default values. - -If your function has ``$`` in the format string, -meaning it takes keyword-only arguments, -specify ``*`` on a line by itself before the first keyword-only argument, -indented the same as the parameter lines. - -:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged. - -Next, if the existing C function calls :c:func:`PyArg_ParseTuple` -(as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its -arguments are positional-only. - -To mark parameters as positional-only in Argument Clinic, -add a ``/`` on a line by itself after the last positional-only parameter, -indented the same as the parameter lines. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -It can be helpful to write a per-parameter docstring for each parameter. -Since per-parameter docstrings are optional, -you can skip this step if you prefer. - -Nevertheless, here's how to add a per-parameter docstring. -The first line of the per-parameter docstring -must be indented further than the parameter definition. -The left margin of this first line establishes -the left margin for the whole per-parameter docstring; -all the text you write will be outdented by this amount. -You can write as much text as you like, across multiple lines if you wish. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -Save and close the file, then run ``Tools/clinic/clinic.py`` on it. -With luck everything worked---your block now has output, -and a :file:`.c.h` file has been generated! -Reload the file in your text editor to see the generated code:: - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - - static PyObject * - _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ - -Obviously, if Argument Clinic didn't produce any output, -it's because it found an error in your input. -Keep fixing your errors and retrying until Argument Clinic processes your file -without complaint. - -For readability, most of the glue code has been generated to a :file:`.c.h` -file. You'll need to include that in your original :file:`.c` file, -typically right after the clinic module block:: - - #include "clinic/_pickle.c.h" - -Double-check that the argument-parsing code Argument Clinic generated -looks basically the same as the existing code. - -First, ensure both places use the same argument-parsing function. -The existing code must call either -:c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; -ensure that the code generated by Argument Clinic calls the -*exact* same function. - -Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or -:c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same -as the hand-written one in the existing function, -up to the colon or semi-colon. - -Argument Clinic always generates its format strings -with a ``:`` followed by the name of the function. -If the existing code's format string ends with ``;``, -to provide usage help, this change is harmless --- don't worry about it. - -Third, for parameters whose format units require two arguments, -like a length variable, an encoding string, or a pointer -to a conversion function, ensure that the second argument is -*exactly* the same between the two invocations. - -Fourth, inside the output portion of the block, -you'll find a preprocessor macro defining the appropriate static -:c:type:`PyMethodDef` structure for this builtin:: - - #define __PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, - -This static structure should be *exactly* the same as the existing static -:c:type:`!PyMethodDef` structure for this builtin. - -If any of these items differ in *any way*, -adjust your Argument Clinic function specification and rerun -``Tools/clinic/clinic.py`` until they *are* the same. - -Notice that the last line of its output is the declaration -of your "impl" function. This is where the builtin's implementation goes. -Delete the existing prototype of the function you're modifying, but leave -the opening curly brace. Now delete its argument parsing code and the -declarations of all the variables it dumps the arguments into. -Notice how the Python arguments are now arguments to this impl function; -if the implementation used different names for these variables, fix it. - -Let's reiterate, just because it's kind of weird. -Your code should now look like this:: - - static return_type - your_function_impl(...) - /*[clinic end generated code: input=..., output=...]*/ - { - ... - -Argument Clinic generated the checksum line and the function prototype just -above it. You should write the opening and closing curly braces for the -function, and the implementation inside. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - - PyDoc_STRVAR(__pickle_Pickler_dump__doc__, - "Write a pickled representation of obj to the open file.\n" - "\n" - ... - static PyObject * - _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ - { - /* Check whether the Pickler was initialized correctly (issue3664). - Developers often forget to call __init__() in their subclasses, which - would trigger a segfault without this check. */ - if (self->write == NULL) { - PyErr_Format(PicklingError, - "Pickler.__init__() was not called by %s.__init__()", - Py_TYPE(self)->tp_name); - return NULL; - } - - if (_Pickler_ClearBuffer(self) < 0) { - return NULL; - } - - ... - -Remember the macro with the :c:type:`PyMethodDef` structure for this function? -Find the existing :c:type:`!PyMethodDef` structure for this -function and replace it with a reference to the macro. If the builtin -is at module scope, this will probably be very near the end of the file; -if the builtin is a class method, this will probably be below but relatively -near to the implementation. - -Note that the body of the macro contains a trailing comma; when you -replace the existing static :c:type:`!PyMethodDef` structure with the macro, -*don't* add a comma to the end. - -Sample:: - - static struct PyMethodDef Pickler_methods[] = { - __PICKLE_PICKLER_DUMP_METHODDEF - __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF - {NULL, NULL} /* sentinel */ - }; - -Argument Clinic may generate new instances of ``_Py_ID``. For example:: - - &_Py_ID(new_unique_py_id) - -If it does, you'll have to run ``make regen-global-objects`` -to regenerate the list of precompiled identifiers at this point. - -Finally, compile, then run the relevant portions of the regression-test suite. -This change should not introduce any new compile-time warnings or errors, -and there should be no externally visible change to Python's behavior, -except for one difference: :py:func:`inspect.signature` run on your function -should now provide a valid signature! - -Congratulations, you've ported your first function to work with Argument Clinic! - - .. _clinic-howtos: How-to guides @@ -1416,7 +742,7 @@ See also :pep:`573`. How to write a custom converter ------------------------------- -A converter is a Python class that inherits from :py:class:`CConverter`. +A converter is a Python class that inherits from :py:class:`~clinic.CConverter`. The main purpose of a custom converter, is for parameters parsed with the ``O&`` format unit --- parsing such a parameter means calling a :c:func:`PyArg_ParseTuple` "converter function". @@ -1432,8 +758,8 @@ write a :py:meth:`!converter_init` method. After *self*, all additional parameters **must** be keyword-only. Any arguments passed to the converter in Argument Clinic will be passed along to your :py:meth:`!converter_init` method. -See :py:class:`CConverter` for a list of members you may wish to specify in -your subclass. +See :py:class:`~clinic.CConverter` for a list of members you may wish to specify +in your subclass. Here's the simplest example of a custom converter, from :cpy-file:`Modules/zlibmodule.c`:: @@ -1495,6 +821,37 @@ You can still use a self converter, a return converter, and specify a *type* argument to the object converter for :c:macro:`METH_O`. +How to convert ``*args`` parameters (starargs / var-positional) +--------------------------------------------------------------- + +There are two converters suitable for ``*args``: *array* and *tuple*. + +Using the *array* converter will provide the implementation function with +a C array *args* of type of :c:type:`PyObject * <PyObject>` and the number +of items in the array as :c:type:`Py_ssize_t` *args_length*. +For example:: + + /*[clinic input] + var_positional_sample + + spam: int + *args: array + [clinic start generated code]*/ + +Using the *tuple* converter will provide the implementation function with +a standard :c:type:`PyTupleObject`. +For example:: + + /*[clinic input] + var_positional_sample + + spam: int + *args: tuple + [clinic start generated code]*/ + +.. versionadded:: 3.11 + + How to convert ``tp_new`` and ``tp_init`` functions --------------------------------------------------- diff --git a/development-tools/clinic/index.rst b/development-tools/clinic/index.rst new file mode 100644 index 0000000000..a6ddd5c721 --- /dev/null +++ b/development-tools/clinic/index.rst @@ -0,0 +1,268 @@ +.. highlight:: c + +.. _clinic: + +*************** +Argument Clinic +*************** + +:author: Larry Hastings + +**Source code:** :cpy-file:`Tools/clinic/clinic.py`. + +Argument Clinic is a preprocessor for CPython C files. +It was introduced in Python 3.4 with :pep:`436`, +in order to provide introspection signatures, +and to generate performant and tailor-made boilerplate code +for argument parsing in CPython builtins, module level functions, and class methods. +This document is divided in four major sections: + +* :ref:`clinic-background` talks about the basic concepts and goals of Argument Clinic. +* :ref:`clinic-reference` describes the command-line interface and Argument Clinic terminology. +* :ref:`clinic-tutorial` guides you through all the steps required to adapt an existing C function to Argument Clinic. +* :ref:`clinic-howtos` details how to handle specific tasks. + +.. toctree:: + :maxdepth: 2 + :hidden: + + tutorial + howto + +.. note:: + + Argument Clinic is considered internal-only + for CPython. Its use is not supported for files outside + CPython, and no guarantees are made regarding backwards + compatibility for future versions. In other words: if you + maintain an external C extension for CPython, you're welcome + to experiment with Argument Clinic in your own code. But the + version of Argument Clinic that ships with the next version + of CPython *could* be totally incompatible and break all your code. + + +.. _clinic-background: + +Background +========== + +Basic concepts +-------------- + +When Argument Clinic is run on a file, either via the :ref:`clinic-cli` +or via ``make clinic``, it will scan over the input files looking for +:term:`start lines <start line>`: + +.. code-block:: none + + /*[clinic input] + +When it finds one, it reads everything up to the :term:`end line`: + +.. code-block:: none + + [clinic start generated code]*/ + +Everything in between these two lines is Argument Clinic :term:`input`. +When Argument Clinic parses input, it generates :term:`output`. +The output is rewritten into the C file immediately after the input, +followed by a :term:`checksum line`. +All of these lines, including the :term:`start line` and :term:`checksum line`, +are collectively called an Argument Clinic :term:`block`: + +.. code-block:: none + + /*[clinic input] + ... clinic input goes here ... + [clinic start generated code]*/ + ... clinic output goes here ... + /*[clinic end generated code: ...]*/ + +If you run Argument Clinic on the same file a second time, Argument Clinic +will discard the old :term:`output` and write out the new output with a fresh +:term:`checksum line`. +If the :term:`input` hasn't changed, the output won't change either. + +.. note:: + + You should never modify the output of an Argument Clinic block, + as any change will be lost in future Argument Clinic runs; + Argument Clinic will detect an output checksum mismatch and regenerate the + correct output. + If you are not happy with the generated output, + you should instead change the input until it produces the output you want. + + +.. _clinic-reference: + +Reference +========= + + +.. _clinic-terminology: + +Terminology +----------- + +.. glossary:: + + start line + The line ``/*[clinic input]``. + This line marks the beginning of Argument Clinic input. + Note that the *start line* opens a C block comment. + + end line + The line ``[clinic start generated code]*/``. + The *end line* marks the *end* of Argument Clinic :term:`input`, + but at the same time marks the *start* of Argument Clinic :term:`output`, + thus the text *"clinic start start generated code"* + Note that the *end line* closes the C block comment opened + by the *start line*. + + checksum + A hash to distinguish unique :term:`inputs <input>` + and :term:`outputs <output>`. + + checksum line + A line that looks like ``/*[clinic end generated code: ...]*/``. + The three dots will be replaced by a :term:`checksum` generated from the + :term:`input`, and a :term:`checksum` generated from the :term:`output`. + The checksum line marks the end of Argument Clinic generated code, + and is used by Argument Clinic to determine if it needs to regenerate + output. + + input + The text between the :term:`start line` and the :term:`end line`. + Note that the start and end lines open and close a C block comment; + the *input* is thus a part of that same C block comment. + + output + The text between the :term:`end line` and the :term:`checksum line`. + + block + All text from the :term:`start line` to the :term:`checksum line` inclusively. + + +.. _clinic-cli: + +Command-line interface +---------------------- + +The Argument Clinic :abbr:`CLI (Command-Line Interface)` is typically used to +process a single source file, like this: + +.. code-block:: shell-session + + $ python3 ./Tools/clinic/clinic.py foo.c + +The CLI supports the following options: + +.. program:: ./Tools/clinic/clinic.py [-h] [-f] [-o OUTPUT] [-v] \ + [--converters] [--make] [--srcdir SRCDIR] [--limited] [FILE ...] + +.. option:: -h, --help + + Print CLI usage. + +.. option:: -f, --force + + Force output regeneration. + +.. option:: -o, --output OUTPUT + + Redirect file output to OUTPUT + +.. option:: -v, --verbose + + Enable verbose mode. + +.. option:: --converters + + Print a list of all supported converters and return converters. + +.. option:: --make + + Walk :option:`--srcdir` to run over all relevant files. + +.. option:: --srcdir SRCDIR + + The directory tree to walk in :option:`--make` mode. + +.. option:: --exclude EXCLUDE + + A file to exclude in :option:`--make` mode. + This option can be given multiple times. + +.. option:: --limited + + Use the :ref:`Limited API <limited-c-api>` to parse arguments in the generated C code. + See :ref:`clinic-howto-limited-capi`. + +.. option:: FILE ... + + The list of files to process. + + +.. _clinic-classes: + +Classes for extending Argument Clinic +------------------------------------- + +.. module:: clinic + +.. class:: CConverter + + The base class for all converters. + See :ref:`clinic-howto-custom-converter` for how to subclass this class. + + .. attribute:: type + + The C type to use for this variable. + :attr:`!type` should be a Python string specifying the type, + for example, ``'int'``. + If this is a pointer type, the type string should end with ``' *'``. + + .. attribute:: default + + The Python default value for this parameter, as a Python value. + Or the magic value ``unspecified`` if there is no default. + + .. attribute:: py_default + + :attr:`!default` as it should appear in Python code, + as a string. + Or ``None`` if there is no default. + + .. attribute:: c_default + + :attr:`!default` as it should appear in C code, + as a string. + Or ``None`` if there is no default. + + .. attribute:: c_ignored_default + + The default value used to initialize the C variable when + there is no default, but not specifying a default may + result in an "uninitialized variable" warning. This can + easily happen when using option groups—although + properly written code will never actually use this value, + the variable does get passed in to the impl, and the + C compiler will complain about the "use" of the + uninitialized value. This value should always be a + non-empty string. + + .. attribute:: converter + + The name of the C converter function, as a string. + + .. attribute:: impl_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into the impl function. + + .. attribute:: parse_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into :c:func:`PyArg_ParseTuple`. diff --git a/development-tools/clinic/tutorial.rst b/development-tools/clinic/tutorial.rst new file mode 100644 index 0000000000..6acfaee4bd --- /dev/null +++ b/development-tools/clinic/tutorial.rst @@ -0,0 +1,408 @@ +.. _clinic-tutorial: + +Tutorial +======== + +The best way to get a sense of how Argument Clinic works is to +convert a function to work with it. Here, then, are the bare +minimum steps you'd need to follow to convert a function to +work with Argument Clinic. Note that for code you plan to +check in to CPython, you really should take the conversion farther, +using some of the :ref:`advanced concepts <clinic-howtos>` +you'll see later on in the document, +like :ref:`clinic-howto-return-converters` +and :ref:`clinic-howto-self-converter`. +But we'll keep it simple for this walkthrough so you can learn. + +First, make sure you're working with a freshly updated checkout +of the CPython trunk. + +Next, find a Python builtin that calls either :c:func:`PyArg_ParseTuple` +or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted +to work with Argument Clinic yet. +For this tutorial, we'll be using +:py:meth:`_pickle.Pickler.dump <pickle.Pickler.dump>`. + +If the call to the :c:func:`!PyArg_Parse*` function uses any of the +following format units...: + +.. code-block:: none + + O& + O! + es + es# + et + et# + +... or if it has multiple calls to :c:func:`PyArg_ParseTuple`, +you should choose a different function. +(See :ref:`clinic-howto-advanced-converters` for those scenarios.) + +Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` +or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different +types for the same argument, or if the function uses something besides +:c:func:`!PyArg_Parse*` functions to parse its arguments, it probably +isn't suitable for conversion to Argument Clinic. Argument Clinic +doesn't support generic functions or polymorphic parameters. + +Next, add the following boilerplate above the function, +creating our input block:: + + /*[clinic input] + [clinic start generated code]*/ + +Cut the docstring and paste it in between the ``[clinic]`` lines, +removing all the junk that makes it a properly quoted C string. +When you're done you should have just the text, based at the left +margin, with no line wider than 80 characters. +Argument Clinic will preserve indents inside the docstring. + +If the old docstring had a first line that looked like a function +signature, throw that line away; The docstring doesn't need it anymore --- +when you use :py:func:`help` on your builtin in the future, +the first line will be built automatically based on the function's signature. + +Example docstring summary line:: + + /*[clinic input] + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +If your docstring doesn't have a "summary" line, Argument Clinic will +complain, so let's make sure it has one. The "summary" line should +be a paragraph consisting of a single 80-column line +at the beginning of the docstring. +(See :pep:`257` regarding docstring conventions.) + +Our example docstring consists solely of a summary line, so the sample +code doesn't have to change for this step. + +Now, above the docstring, enter the name of the function, followed +by a blank line. This should be the Python name of the function, +and should be the full dotted path to the function --- +it should start with the name of the module, +include any sub-modules, and if the function is a method on +a class it should include the class name too. + +In our example, :mod:`!_pickle` is the module, :py:class:`!Pickler` is the class, +and :py:meth:`!dump` is the method, so the name becomes +:py:meth:`!_pickle.Pickler.dump`:: + + /*[clinic input] + _pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +If this is the first time that module or class has been used with Argument +Clinic in this C file, +you must declare the module and/or class. Proper Argument Clinic hygiene +prefers declaring these in a separate block somewhere near the +top of the C file, in the same way that include files and statics go at +the top. +In our sample code we'll just show the two blocks next to each other. + +The name of the class and module should be the same as the one +seen by Python. Check the name defined in the :c:type:`PyModuleDef` +or :c:type:`PyTypeObject` as appropriate. + +When you declare a class, you must also specify two aspects of its type +in C: the type declaration you'd use for a pointer to an instance of +this class, and a pointer to the :c:type:`!PyTypeObject` for this class:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + + /*[clinic input] + _pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +Declare each of the parameters to the function. Each parameter +should get its own line. All the parameter lines should be +indented from the function name and the docstring. +The general form of these parameter lines is as follows: + +.. code-block:: none + + name_of_parameter: converter + +If the parameter has a default value, add that after the +converter: + +.. code-block:: none + + name_of_parameter: converter = default_value + +Argument Clinic's support for "default values" is quite sophisticated; +see :ref:`clinic-howto-default-values` for more information. + +Next, add a blank line below the parameters. + +What's a "converter"? +It establishes both the type of the variable used in C, +and the method to convert the Python value into a C value at runtime. +For now you're going to use what's called a "legacy converter" --- +a convenience syntax intended to make porting old code into Argument +Clinic easier. + +For each parameter, copy the "format unit" for that +parameter from the :c:func:`PyArg_Parse` format argument and +specify *that* as its converter, as a quoted string. +The "format unit" is the formal name for the one-to-three +character substring of the *format* parameter that tells +the argument parsing function what the type of the variable +is and how to convert it. +For more on format units please see :ref:`arg-parsing`. + +For multicharacter format units like ``z#``, +use the entire two-or-three character string. + +Sample:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + + /*[clinic input] + _pickle.Pickler.dump + + obj: 'O' + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +If your function has ``|`` in the format string, +meaning some parameters have default values, you can ignore it. +Argument Clinic infers which parameters are optional +based on whether or not they have default values. + +If your function has ``$`` in the format string, +meaning it takes keyword-only arguments, +specify ``*`` on a line by itself before the first keyword-only argument, +indented the same as the parameter lines. + +:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged. + +Next, if the existing C function calls :c:func:`PyArg_ParseTuple` +(as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its +arguments are positional-only. + +To mark parameters as positional-only in Argument Clinic, +add a ``/`` on a line by itself after the last positional-only parameter, +indented the same as the parameter lines. + +Sample:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + + /*[clinic input] + _pickle.Pickler.dump + + obj: 'O' + / + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +It can be helpful to write a per-parameter docstring for each parameter. +Since per-parameter docstrings are optional, +you can skip this step if you prefer. + +Nevertheless, here's how to add a per-parameter docstring. +The first line of the per-parameter docstring +must be indented further than the parameter definition. +The left margin of this first line establishes +the left margin for the whole per-parameter docstring; +all the text you write will be outdented by this amount. +You can write as much text as you like, across multiple lines if you wish. + +Sample:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + + /*[clinic input] + _pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + +Save and close the file, then run ``Tools/clinic/clinic.py`` on it. +With luck everything worked---your block now has output, +and a :file:`.c.h` file has been generated! +Reload the file in your text editor to see the generated code:: + + /*[clinic input] + _pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + + static PyObject * + _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) + /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ + +Obviously, if Argument Clinic didn't produce any output, +it's because it found an error in your input. +Keep fixing your errors and retrying until Argument Clinic processes your file +without complaint. + +For readability, most of the glue code has been generated to a :file:`.c.h` +file. You'll need to include that in your original :file:`.c` file, +typically right after the clinic module block:: + + #include "clinic/_pickle.c.h" + +Double-check that the argument-parsing code Argument Clinic generated +looks basically the same as the existing code. + +First, ensure both places use the same argument-parsing function. +The existing code must call either +:c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; +ensure that the code generated by Argument Clinic calls the +*exact* same function. + +Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or +:c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same +as the hand-written one in the existing function, +up to the colon or semi-colon. + +Argument Clinic always generates its format strings +with a ``:`` followed by the name of the function. +If the existing code's format string ends with ``;``, +to provide usage help, this change is harmless --- don't worry about it. + +Third, for parameters whose format units require two arguments, +like a length variable, an encoding string, or a pointer +to a conversion function, ensure that the second argument is +*exactly* the same between the two invocations. + +Fourth, inside the output portion of the block, +you'll find a preprocessor macro defining the appropriate static +:c:type:`PyMethodDef` structure for this builtin:: + + #define __PICKLE_PICKLER_DUMP_METHODDEF \ + {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, + +This static structure should be *exactly* the same as the existing static +:c:type:`!PyMethodDef` structure for this builtin. + +If any of these items differ in *any way*, +adjust your Argument Clinic function specification and rerun +``Tools/clinic/clinic.py`` until they *are* the same. + +Notice that the last line of its output is the declaration +of your "impl" function. This is where the builtin's implementation goes. +Delete the existing prototype of the function you're modifying, but leave +the opening curly brace. Now delete its argument parsing code and the +declarations of all the variables it dumps the arguments into. +Notice how the Python arguments are now arguments to this impl function; +if the implementation used different names for these variables, fix it. + +Let's reiterate, just because it's kind of weird. +Your code should now look like this:: + + static return_type + your_function_impl(...) + /*[clinic end generated code: input=..., output=...]*/ + { + ... + +Argument Clinic generated the checksum line and the function prototype just +above it. You should write the opening and closing curly braces for the +function, and the implementation inside. + +Sample:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /*[clinic input] + _pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + + PyDoc_STRVAR(__pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) + /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + { + /* Check whether the Pickler was initialized correctly (issue3664). + Developers often forget to call __init__() in their subclasses, which + would trigger a segfault without this check. */ + if (self->write == NULL) { + PyErr_Format(PicklingError, + "Pickler.__init__() was not called by %s.__init__()", + Py_TYPE(self)->tp_name); + return NULL; + } + + if (_Pickler_ClearBuffer(self) < 0) { + return NULL; + } + + ... + +Remember the macro with the :c:type:`PyMethodDef` structure for this function? +Find the existing :c:type:`!PyMethodDef` structure for this +function and replace it with a reference to the macro. If the builtin +is at module scope, this will probably be very near the end of the file; +if the builtin is a class method, this will probably be below but relatively +near to the implementation. + +Note that the body of the macro contains a trailing comma; when you +replace the existing static :c:type:`!PyMethodDef` structure with the macro, +*don't* add a comma to the end. + +Sample:: + + static struct PyMethodDef Pickler_methods[] = { + __PICKLE_PICKLER_DUMP_METHODDEF + __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF + {NULL, NULL} /* sentinel */ + }; + +Argument Clinic may generate new instances of ``_Py_ID``. For example:: + + &_Py_ID(new_unique_py_id) + +If it does, you'll have to run ``make regen-global-objects`` +to regenerate the list of precompiled identifiers at this point. + +Finally, compile, then run the relevant portions of the regression-test suite. +This change should not introduce any new compile-time warnings or errors, +and there should be no externally visible change to Python's behavior, +except for one difference: :py:func:`inspect.signature` run on your function +should now provide a valid signature! + +Congratulations, you've ported your first function to work with Argument Clinic! diff --git a/development-tools/gdb.rst b/development-tools/gdb.rst index 8f89ea1360..835b2dbc70 100644 --- a/development-tools/gdb.rst +++ b/development-tools/gdb.rst @@ -29,7 +29,7 @@ this approach is less helpful when debugging the runtime virtual machine, since the main interpreter loop function, ``_PyEval_EvalFrameDefault``, is well over 4,000 lines long as of Python 3.12. Fortunately, among the `many ways to set breakpoints -<https://sourceware.org/gdb/current/onlinedocs/gdb.html/Location-Specifications.html>`_, +<https://sourceware.org/gdb/current/onlinedocs/gdb.html/Location-Specifications.html>`__, you can break at C labels, such as those generated for computed gotos. If you are debugging an interpreter compiled with computed goto support (generally true, certainly when using GCC), each instruction will be diff --git a/development-tools/index.rst b/development-tools/index.rst index 5031227a18..b564c933e8 100644 --- a/development-tools/index.rst +++ b/development-tools/index.rst @@ -7,7 +7,7 @@ Development tools .. toctree:: :maxdepth: 5 - clinic + clinic/index gdb clang warnings diff --git a/development-tools/warnings.rst b/development-tools/warnings.rst index b6448f3979..b30d811311 100644 --- a/development-tools/warnings.rst +++ b/development-tools/warnings.rst @@ -37,15 +37,18 @@ platform-specific warning ignore file. The warning ignore file is either If a warning check fails with: * Unexpected warnings - * Attempt to refactor the code to avoid the warning. - * If it is not possible to avoid the warning document in the PR why it is - reasonable to ignore and add the warning to the platform-specific - warning ignore file. If the file exists in the warning ignore file - increment the count by the number of newly introduced warnings. + + * Attempt to refactor the code to avoid the warning. + * If it is not possible to avoid the warning document in the PR why it is + reasonable to ignore and add the warning to the platform-specific + warning ignore file. If the file exists in the warning ignore file + increment the count by the number of newly introduced warnings. + * Unexpected improvements (less warnings) - * Document in the PR that the change reduces the number of compiler - warnings. Decrement the count in the platform-specific warning - ignore file or remove the file if the count is now zero. + + * Document in the PR that the change reduces the number of compiler + warnings. Decrement the count in the platform-specific warning + ignore file or remove the file if the count is now zero. .. _updating-warning-ignore-file: diff --git a/documentation/devguide.rst b/documentation/devguide.rst index 7c53d054e1..74f734831b 100644 --- a/documentation/devguide.rst +++ b/documentation/devguide.rst @@ -4,13 +4,7 @@ Helping with the Developer's Guide ================================== -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst .. highlight:: console @@ -22,8 +16,8 @@ lives in a `separate repository`_ and bug reports should be submitted to the Changes to the Developer's Guide are published when pull requests are merged. Changes to the Python documentation are published regularly, -ususally within 48 hours of the change being committed. -The documentation is also `published for each release <https://docs.python.org/release/>`_, +usually within 48 hours of the change being committed. +The documentation is also `published for each release <https://docs.python.org/release/>`__, which may also be used by redistributors. diff --git a/documentation/help-documenting.rst b/documentation/help-documenting.rst index 0b287df928..23520375cb 100644 --- a/documentation/help-documenting.rst +++ b/documentation/help-documenting.rst @@ -37,8 +37,8 @@ The in-development and recent maintenance branches are rebuilt once per day. If you would like to be more involved with documentation, consider subscribing to the `Documentation category on the Python Discourse -<https://discuss.python.org/c/documentation/26>`_ and the -`docs@python.org <https://mail.python.org/mailman3/lists/docs.python.org/>`_ mailing list +<https://discuss.python.org/c/documentation/26>`__ and the +`docs@python.org <https://mail.python.org/mailman3/lists/docs.python.org/>`__ mailing list where user issues are raised and documentation toolchain, projects, and standards are discussed. @@ -65,7 +65,14 @@ By following the steps in the :ref:`Quick Guide to Pull Requests <pullrequest-qu you will learn the workflow for documentation pull requests. .. _documentation issues: https://github.com/python/cpython/issues?q=is%3Aissue+is%3Aopen+label%3Adocs -.. _octocat: https://github.com/logos + + +Translating +=========== + +The Python documentation is being actively translated into several languages. +If you are interested in helping with translation, see our pages on +:ref:`translating <translating>` to get started. Proofreading diff --git a/documentation/index.rst b/documentation/index.rst index 3f2512bcfb..eaa9e1a967 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -9,5 +9,5 @@ Documentation help-documenting style-guide markup - translating + translations/index devguide diff --git a/documentation/markup.rst b/documentation/markup.rst index 9528075d96..863fe34443 100644 --- a/documentation/markup.rst +++ b/documentation/markup.rst @@ -22,13 +22,13 @@ Element Markup See also arguments/parameters ``*arg*`` :ref:`inline-markup` variables/literals/code ````foo````, ````42````, ````len(s) - 1```` :ref:`inline-markup` True/False/None ````True````, ````False````, ````None```` :ref:`inline-markup` -function definitions ``.. function:: print(*args)`` :ref:`directives` -function references ``:func:`print``` :ref:`roles` +function definitions ``.. function:: print(*args)`` :ref:`directives` +function references ``:func:`print``` :ref:`roles` attribute definitions ``.. attribute: `attr-name``` :ref:`information-units` attribute references ``:attr:`attr-name``` :ref:`roles` reference labels ``.. _label-name:`` :ref:`doc-ref-role` internal references ``:ref:`label-name``` :ref:`doc-ref-role` -external links ```Link text <https://example.com>`_`` :ref:`hyperlinks` +external links ```Link text <https://example.com>`__`` :ref:`hyperlinks` roles w/ custom text ``:role:`custom text <target>``` :ref:`roles` roles w/ only last part ``:role:`~hidden.hidden.visible``` :ref:`roles` roles w/o link ``:role:`!target``` :ref:`roles` @@ -51,7 +51,7 @@ language, this will not take too long. .. seealso:: The authoritative `reStructuredText User - Documentation <https://docutils.sourceforge.io/rst.html>`_. + Documentation <https://docutils.sourceforge.io/rst.html>`__. Use of whitespace @@ -185,9 +185,12 @@ Hyperlinks External links ^^^^^^^^^^^^^^ -Use ```Link text <http://target>`_`` for inline web links. If the link text +Use ```Link text <https://example.com>`__`` for inline web links. If the link text should be the web address, you don't need special markup at all, the parser -finds links and mail addresses in ordinary text. +finds links and mail addresses in ordinary text. Prefer anonymous hyperlinks +(with a double underscore) over named hyperlinks (with a single underscore) +to avoid target name clashes. + Internal links ^^^^^^^^^^^^^^ @@ -343,23 +346,7 @@ they are used in the Python documentation. This is just an overview of Sphinx' extended markup capabilities; full coverage can be found in `its own documentation - <https://www.sphinx-doc.org/>`_. - - -Meta-information markup ------------------------ - -.. describe:: sectionauthor - - Identifies the author of the current section. The argument should include - the author's name such that it can be used for presentation (though it isn't) - and email address. The domain name portion of the address should be lower - case. Example:: - - .. sectionauthor:: Guido van Rossum <guido@python.org> - - Currently, this markup isn't reflected in the output in any way, but it helps - keep track of contributions. + <https://www.sphinx-doc.org/>`__. Module-specific markup @@ -370,17 +357,11 @@ module being documented. Each module should be documented in its own file. Normally this markup appears after the title heading of that file; a typical file might start like this:: - :mod:`parrot` -- Dead parrot access - =================================== + :mod:`!parrot` -- Dead parrot access + ==================================== .. module:: parrot - :platform: Unix, Windows :synopsis: Analyze and reanimate dead parrots. - .. moduleauthor:: Eric Cleese <eric@python.invalid> - .. moduleauthor:: John Idle <john@python.invalid> - -As you can see, the module-specific markup consists of two directives, the -``module`` directive and the ``moduleauthor`` directive. .. describe:: module @@ -388,24 +369,12 @@ As you can see, the module-specific markup consists of two directives, the or submodule. The name should be fully qualified (that is, including the package name for submodules). - The ``platform`` option, if present, is a comma-separated list of the - platforms on which the module is available (if it is available on all - platforms, the option should be omitted). The keys are short identifiers; - examples that are in use include "IRIX", "Mac", "Windows", and "Unix". It is - important to use a key which has already been used when applicable. - The ``synopsis`` option should consist of one sentence describing the module's purpose -- it is currently only used in the Global Module Index. The ``deprecated`` option can be given (with no value) to mark a module as deprecated; it will be designated as such in various locations then. -.. describe:: moduleauthor - - The ``moduleauthor`` directive, which can appear multiple times, names the - authors of the module code, just like ``sectionauthor`` names the author(s) - of a piece of documentation. It too does not result in any output currently. - .. note:: It is important to make the section title of a module-describing file @@ -544,8 +513,8 @@ The directives are: Set name of the decorated function to *name*. - There is no ``deco`` role to link to a decorator that is marked up with - this directive; rather, use the ``:func:`` role. + To link to a decorator that is marked up with this directive, + use the ``:deco:`` role. .. describe:: class @@ -806,6 +775,10 @@ a matching identifier is found: The name of an exception. A dotted name may be used. +.. describe:: deco + + The name of a decorator. A dotted name may be used. + The name enclosed in this markup can include a module name and/or a class name. For example, ``:func:`filter``` could refer to a function named ``filter`` in the current module, or the built-in function of that name. In contrast, @@ -1050,6 +1023,17 @@ Paragraph-level markup These directives create short paragraphs and can be used inside information units as well as normal text: +.. describe:: availability + + This directive documents the platforms on which a module or feature + is available. For example:: + + .. availability:: Unix, not WASI, not Android. + + :: + + .. availability:: Linux >= 3.0 with glibc >= 2.14. + .. describe:: note An especially important bit of information about an API that a user should be @@ -1215,6 +1199,9 @@ units as well as normal text: Table-of-contents markup ------------------------ +.. TODO: This is a copy of the Sphinx description of the toctree directive. + Why duplicate it here? + Since reST does not have facilities to interconnect several documents, or split documents into multiple output files, Sphinx uses a custom directive to add relations between the single files the documentation is made of, as well as diff --git a/documentation/start-documenting.rst b/documentation/start-documenting.rst index 184cf54bfd..917cb30bfa 100644 --- a/documentation/start-documenting.rst +++ b/documentation/start-documenting.rst @@ -5,13 +5,7 @@ Getting started =============== -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst .. highlight:: rest @@ -76,12 +70,22 @@ To build the documentation, follow the steps in one of the sections below. You can view the documentation after building the HTML by opening the file :file:`Doc/build/html/index.html` in a web browser. -.. note:: +Initial requirements +-------------------- + +Ensure your current working directory is the top level ``Doc/`` directory +inside your :ref:`CPython repository clone <checkout>`. You can switch to +it with: + +.. code-block:: shell + + cd Doc - The following instructions all assume your current working dir is - the ``Doc`` subdirectory in your :ref:`CPython repository clone <checkout>`. - Make sure to switch to it with ``cd Doc`` if necessary. +Ensure your Python version is at least 3.11. You can verify it with: +.. code-block:: shell + + python --version .. _doc-create-venv: @@ -152,6 +156,27 @@ To build the docs as HTML, run: * Replace ``html`` with ``htmllive`` to rebuild the docs, start a local server, and automatically reload the page in your browser when you make changes to reST files (Unix only). + * To build a documentation translation, see this + :ref:`guide <docs-build-translation>`. + +It is also possible to build only certain pages of the documentation in order +to save time during the build process. Following is an example for building two +pages: + +.. tab:: Unix/macOS + + .. code-block:: shell + + make html SOURCES="tutorial/classes.rst tutorial/inputoutput.rst" + +.. tab:: Windows + + See :ref:`using-sphinx-build`. When invoking ``sphinx-build``, pass the + desired pages as the final parameter, like so: + + .. code-block:: dosbatch + + python -m sphinx -b html . build/html tutorial/classes.rst tutorial/inputoutput.rst To check the docs for common errors with `Sphinx Lint`_ (which is run on all :ref:`pull requests <pullrequest>`), use: diff --git a/documentation/style-guide.rst b/documentation/style-guide.rst index 49bd15b1d3..5ca2960cea 100644 --- a/documentation/style-guide.rst +++ b/documentation/style-guide.rst @@ -66,8 +66,14 @@ Specific words Some terms and words deserve special mention. These conventions should be used to ensure consistency throughout the documentation: +boolean + Lowercase in most instances. + Uppercase for *Boolean mathematics* and *Boolean logic*. + To refer to the Python or C data type, prefer using the exact, + abbreviated name with appropriate markup (for example, ``:type:`bool```). + C API - Python's `API <https://docs.python.org/3/c-api/>`_ used by C programmers + Python's `API <https://docs.python.org/3/c-api/>`__ used by C programmers to write extension modules. All caps and unhyphenated. CPU @@ -110,13 +116,31 @@ Don't use Latin abbreviations like "e.g." or "i.e." where English words will do, such as "for example" or "that is." +Charged terminology to avoid +============================ + +Avoid terminology that may be considered insensitive or exclusionary. + +.. list-table:: + :header-rows: 1 + + * - Avoid + - Instead + * - whitelist + - allowlist + * - blacklist + - blocklist, denylist + * - master/slave + - main, parent/child, server/client, primary/secondary + + .. index:: diataxis .. _diataxis: Diátaxis ======== -Python's documentation strives to follow the `Diátaxis <https://diataxis.fr/>`_ +Python's documentation strives to follow the `Diátaxis <https://diataxis.fr/>`__ framework. This means adapting the writing style according to the nature of the documentation that is being written. The framework splits documentation into four distinct types: tutorials, how-to guides, reference, and @@ -129,7 +153,7 @@ explanation. and abstract concepts should be avoided. Please consult the Diátaxis guide on :ref:`diataxis:tutorials` for more detail. -* `Python how-to guides <https://docs.python.org/3/howto/index.html>`_ are +* `Python how-to guides <https://docs.python.org/3/howto/index.html>`__ are designed to guide a user through a problem-field. Both tutorials and how-to guides are instructional rather than explanatory and should provide logical steps on how to complete a task. However, @@ -152,7 +176,7 @@ explanation. found throughout Python's documentation, for example the :ref:`python:unicode-howto`. -Please consult the `Diátaxis <https://diataxis.fr/>`_ guide for more +Please consult the `Diátaxis <https://diataxis.fr/>`__ guide for more detail. @@ -169,18 +193,19 @@ the second mention is more appropriate for a link. Some units are long enough to have a few repeated links. Use judgement to decide when a link will help the reader. -Do not use a link when the link would point to the current unit. It's natural -to use the name of a function in the documentation for the function, but a link -on that function name that simply reloads the section the user is already -reading is useless and distracting. +We use the :pypi:`linklint Sphinx extension <linklint>` to suppress two kinds +of excessive links: references in a section to itself and duplicate references +in a paragraph. Previously, editors had to carefully use an exclamation mark +in a Sphinx reference (``:func:`!map```) to prevent such links. Do not use links in section headers. They distract from the title of the section. The term will be mentioned in the paragraph text and can be linked from there. -Sphinx provides ways to automatically add links to references, and a way to +Sphinx automatically adds links to references, and provides a way to suppress the link. Using roles like ``:func:`map``` will link to the -documentation for ``map``. You can suppress the link while keeping the +documentation for ``map``. If automatic link suppression isn't enough, +you can suppress the link while keeping the semantic presentation of the function name by adding an exclamation point prefix: ``:func:`!map```. See :ref:`roles` for more details. @@ -218,8 +243,8 @@ For new documentation, do not use a byline (naming the author of the document). Explicit attribution tends to discourage other users from updating community documentation. -Existing documentation with bylines will not be changed unless the author -decides to do so. This is subject to change in the future. +Existing bylines are for historical interest only. They do not imply ownership +or necessary approvals, and do not prevent edits or updates by others. Pronunciation of dunder names diff --git a/documentation/translating.rst b/documentation/translating.rst deleted file mode 100644 index a2d1870a4a..0000000000 --- a/documentation/translating.rst +++ /dev/null @@ -1,246 +0,0 @@ -.. _translating: - -=========== -Translating -=========== - -.. highlight:: rest - -Python documentation translations are governed by :PEP:`545`. -They are built by `docsbuild-scripts -<https://github.com/python/docsbuild-scripts/>`__ and hosted on -docs.python.org. There are several documentation translations already -in production; others are works in progress. See `the dashboard -<https://m-aciek.github.io/pydocs-translation-dashboard/>`__ for -details. - -.. list-table:: - :header-rows: 1 - - * - Language - - Contact - - Links - * - Arabic (ar) - - Abdur-Rahmaan Janhangeer (:github-user:`Abdur-rahmaanJ`) - - :github:`GitHub <Abdur-rahmaanJ/python-docs-ar>` - * - Bengali as spoken in India (bn_IN) - - Kushal Das (:github-user:`Kushal997-das`) - - :github:`GitHub <python/python-docs-bn-in>` - * - `French (fr) <https://docs.python.org/fr/>`__ - - Julien Palard (:github-user:`JulienPalard`) - - :github:`GitHub <python/python-docs-fr>` - * - Greek (gr) - - Lysandros Nikolaou (:github-user:`lysnikolaou`), - Fanis Petkos (:github-user:`thepetk`), - Panagiotis Skias (:github-user:`skpanagiotis`) - - :github:`GitHub <pygreece/python-docs-gr>` - * - Hindi as spoken in India (hi_IN) - - Sanyam Khurana (:github-user:`CuriousLearner`) - - :github:`GitHub <CuriousLearner/python-docs-hi-in>` - * - Hungarian (hu) - - Tamás Bajusz (:github-user:`gbtami`) - - :github:`GitHub <python/python-docs-hu>`, - `mailing list <https://mail.python.org/pipermail/python-hu>`__ - * - `Indonesian (id) <https://docs.python.org/id/>`__ - - Oon Arfiandwi (:github-user:`oonid`) - - :github:`GitHub <python/python-docs-id>` - * - Italian (it) - - Alessandro Cucci (`email <mailto:alessandro.cucci@gmail.com>`__) - - :github:`GitHub <python/python-docs-it>`, - `original mail <https://mail.python.org/pipermail/doc-sig/2019-April/004114.html>`__ - * - `Japanese (ja) <https://docs.python.org/ja/>`__ - - Kinebuchi Tomohiko (:github-user:`cocoatomo`), - Atsuo Ishimoto (:github-user:`atsuoishimoto`) - - :github:`GitHub <python/python-docs-ja>` - * - `Korean (ko) <https://docs.python.org/ko/>`__ - - 오동권 (:github-user:`flowdas`) - - :github:`GitHub <python/python-docs-ko>` - * - Marathi (mr) - - Sanket Garade (:github-user:`sanketgarade`, `email <mailto:garade@pm.me>`__) - - :github:`GitHub <sanketgarade/python-doc-mr>` - * - Lithuanian (lt) - - Albertas Gimbutas (:github-user:`albertas`, `email <mailto:albertasgim@gmail.com>`__) - - `Original mail <https://mail.python.org/pipermail/doc-sig/2019-July/004138.html>`__ - * - Persian (fa) - - Komeil Parseh (:github-user:`mmdbalkhi`) - - :github:`GitHub <mmdbalkhi/python-docs-fa>` - * - `Polish (pl) <https://docs.python.org/pl/>`__ - - Maciej Olko (:github-user:`m-aciek`) - - :github:`GitHub <python/python-docs-pl>`, - `Transifex <tx_>`_, - `original mail <https://mail.python.org/pipermail/doc-sig/2019-April/004106.html>`__ - * - Portuguese (pt) - - Gustavo Toffo - - - * - `Portuguese as spoken in Brasil (pt-br) <https://docs.python.org/pt-br/>`__ - - Marco Rougeth - - :github:`GitHub <python/python-docs-pt-br>`, - `wiki <https://python.org.br/traducao/>`__, - `Telegram <https://t.me/pybr_i18n>`__, - `article <https://rgth.co/blog/python-ptbr-cenario-atual/>`__ - * - Russian (ru) - - Daniil Kolesnikov (:github-user:`MLGRussianXP`, `email <mailto:mlgrussianxp@gmail.com>`__) - - :github:`GitHub <MLGRussianXP/python-docs-ru>`, - `mail <https://mail.python.org/pipermail/doc-sig/2019-May/004131.html>`__ - * - `Simplified Chinese (zh-cn) <https://docs.python.org/zh-cn/>`__ - - Shengjing Zhu (:github-user:`zhsj`), - Du, Meng (:github-user:`dumeng`) - - :github:`GitHub <python/python-docs-zh-cn>`, - `Transifex <tx_>`_ - * - `Spanish (es) <https://docs.python.org/es/>`__ - - Raúl Cumplido - - :github:`GitHub <python/python-docs-es>` - * - `Traditional Chinese (zh-tw) <https://docs.python.org/zh-tw/>`__ - - 王威翔 Matt Wang (:github-user:`mattwang44`), - Josix Wang - - :github:`GitHub <python/python-docs-zh-tw>` - * - `Turkish (tr) <https://docs.python.org/tr/>`__ - - Ege Akman (:github-user:`egeakman`) - - :github:`GitHub <python/python-docs-tr>`, - `RTD <https://python-docs-tr.readthedocs.io/>`__ - * - `Ukrainian (uk) <https://docs.python.org/uk/>`__ - - Dmytro Kazanzhy (:github-user:`kazanzhy`, `email <mailto:dkazanzhy@gmail.com>`__) - - :github:`GitHub <python/python-docs-uk>`, - `Transifex <tx_>`_ - -.. _tx: https://explore.transifex.com/python-doc/python-newest/ - -Starting a new translation -========================== - -First subscribe to the `translation mailing list <translation_ml_>`_, -and introduce yourself and the translation you're starting. Translations -fall under the aegis of the `PSF Translation Workgroup <translation_wg_>`_ - -Then you can bootstrap your new translation by using our `cookiecutter -<https://github.com/JulienPalard/python-docs-cookiecutter>`__. - -The important steps look like this: - -- Create the GitHub repo (anywhere) with the right hierarchy (using the - cookiecutter). -- Gather people to help you translate. You can't do it alone. -- You can use any tool to translate, as long as you can synchronize with Git. - Some use Transifex, and some use only GitHub. You can choose another - way if you like; it's up to you. -- Ensure we update this page to reflect your work and progress, either via a - PR or by asking on the `translation mailing list <translation_ml_>`_. -- When ``bugs.html``, ``tutorial``, and ``library/functions`` are 100% - completed, ask on the `translation mailing list <translation_ml_>`_ for - your language to be added in the language picker on docs.python.org. - - -PEP 545 summary -=============== - -Here are the essential points of :PEP:`545`: - -- Each translation is assigned an appropriate lowercased language tag, - with an optional region subtag, and joined with a dash, like - ``pt-br`` or ``fr``. - -- Each translation is under CC0 and marked as such in the README (as in - the cookiecutter). - -- Translation files are hosted on - ``https://github.com/python/python-docs-{LANGUAGE_TAG}`` (not - mandatory to start a translation, but mandatory to land on - ``docs.python.org``). - -- Translations having completed ``tutorial/``, ``library/stdtypes`` - and ``library/functions`` are hosted on - ``https://docs.python.org/{LANGUAGE_TAG}/{VERSION_TAG}/``. - - -How to get help -=============== - -Discussions about translations occur on the Python Docs Discord -`#translations channel <https://discord.gg/h3qDwgyzga>`_, `translation -mailing list <translation_ml_>`_, and there's a `Libera.Chat IRC -<https://libera.chat/>`_ channel, ``#python-doc``. - - -Translation FAQ -=============== - -Which version of the Python documentation should be translated? ---------------------------------------------------------------- - -Consensus is to work on current stable. You can then propagate your -translation from one branch to another using :pypi:`pomerge`. - - -Are there some tools to help in managing the repo? --------------------------------------------------- - -Here's what we're using: - -- :pypi:`pomerge` to propagate translations from one file to others. -- :pypi:`pospell` to check for typos in ``.po`` files. -- :pypi:`powrap` to rewrap the ``.po`` files - before committing. This helps keep Git diffs short. -- :pypi:`potodo` to list what needs to be translated. -- :pypi:`sphinx-lint` to validate reST syntax in translation files. - - -How is a coordinator elected? ------------------------------ - -There is no election; each translation has to sort this out. Here are some suggestions. - -- Coordinator requests are to be public on the `translation mailing list <translation_ml_>`_. -- If the given language has a native core dev, the core dev has their - say on the choice. -- Anyone who wants to become coordinator for their native language and shows - motivation by translating and building a community will be named - coordinator. -- In case of concurrency between two persons, no one will sort this out - for you. It is up to you two to organize a local election or whatever is - needed to sort this out. -- If a coordinator becomes inactive or unreachable for a long - period of time, someone else can ask for a takeover on the `translation mailing list <translation_ml_>`_. - - -The entry for my translation is missing/not up to date on this page -------------------------------------------------------------------- - -Ask on the `translation mailing list <translation_ml_>`_, or better, make a PR on the `devguide -<https://github.com/python/devguide/>`__. - - -I have a translation, but it's not in Git. What should I do? ------------------------------------------------------------- - -You can ask for help on the `translation mailing list <translation_ml_>`_, and -the team will help you create an appropriate repository. You can still use tools like transifex, -if you like. - - -My Git hierarchy does not match yours. Can I keep it? ------------------------------------------------------ - -No, inside the ``github.com/python`` organization we’ll all have the -exact same hierarchy so bots will be able to build all of our -translations. So you may have to convert from one hierarchy to another. -Ask for help on the `translation mailing list <translation_ml_>`_ if you’re -not sure on how to do it. - - -What hierarchy should I use in my GitHub repository? ----------------------------------------------------- - -As for every project, we have a *branch* per version. We store ``.po`` -files in the root of the repository using the ``gettext_compact=0`` -style. - - -How should I translate code examples? -------------------------------------- - -Translate values in code examples (i.e. string literals) and comments. -Don't translate keywords or names, -including variable, function, class, argument, and attribute names. - -.. _translation_wg: https://wiki.python.org/psf/TranslationWG/Charter -.. _translation_ml: https://mail.python.org/mailman3/lists/translation.python.org/ diff --git a/documentation/translations/coordinating.rst b/documentation/translations/coordinating.rst new file mode 100644 index 0000000000..82cfce74fa --- /dev/null +++ b/documentation/translations/coordinating.rst @@ -0,0 +1,300 @@ +============ +Coordinating +============ + +Information about the Python documentation translation processes is +found on this page and in :PEP:`545`. Translations are overseen by the +`Editorial Board <EB_>`_. + +.. _translation-help: + +Communication/help channels +=========================== + +Discussions about translations occur on the Python Docs Discord +`#translations channel <https://discord.gg/h3qDwgyzga>`__ and the +`translations category <trans_disc_>`_ of the Python Discourse. + +For administrative issues, ping ``@python/editorial-board``. + + +Starting a new translation +========================== + +Coordination is not a one-off task, it is a long-term commitment. Before +you start your translation, carefully consider if you will be able to commit +to this. +Every coordinator should be familiar with translating: see :ref:`translating`. + +The following sections will guide you through setting up your translation. +If you have any questions or need help, ask in one of the +:ref:`help channels <translation-help>`. + + +Announcement +------------ + +Post an announcement introducing yourself and the translation you're +starting on `Discourse <trans_disc_>`_. Also join the other communication +channels, if possible. + + +Coordination team +----------------- + +Each translation team will decide on the number of coordinators. +While initially one person is fine, we recommend expanding to having two or +three coordinators. You can find more on choosing coordinators in the FAQ +section on this page. + + +Translation team +---------------- + +.. figure:: translator-workload.svg + :class: invert-in-dark-mode + :align: center + :alt: An exaggerated chart showing that individual translator workload + decreases with the number of translators. + + +Gather people to translate with you. You can't do it alone. +Update :ref:`this table <translation-coordinators>` via a PR on the devguide +to make your translation easier to find. In the entry you can also include links +to guides or other resources for translators. + + +.. _translation-repo: + +Repository +---------- + +To start your translation create a GitHub repository, under any +account, with the correct Git hierarchy and folder structure. This can be done +in several ways, and depends on what translation process you plan to use. + +Each translation is assigned an appropriate lowercase +`IETF language tag <https://datatracker.ietf.org/doc/html/rfc5646.html>`__. +The tag may have an optional subtag, joined with a dash. +For example, ``pt`` (Portuguese) or ``pt-br`` (Brazilian Portuguese). +The repository name is then: ``python-docs-TAG`` + +The name of each branch should be the Python version it holds translations +for, for example, ``3.14``. The files should be structured like the source files +in `CPython/Doc <https://github.com/python/cpython/tree/main/Doc>`__. +A correctly set up repository looks like this: +`python-docs-pl <https://github.com/python/python-docs-pl/>`__ + +Below, the recommended ways for starting your repository are described. You can +choose another way if you like; it’s up to you. + + +Cookiecutter/bootstrapper +~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can bootstrap your new translation by using the `cookiecutter +<https://github.com/python-docs-translations/python-docs-cookiecutter>`__ or +`bootstrapper <https://github.com/python-docs-translations/python-docs-bootstrapper>`__. +The repository can then be used with a pull-request based translation process. + + +Translation platform +~~~~~~~~~~~~~~~~~~~~ + +You can also start your translation using +`Transifex <https://explore.transifex.com/python-doc/python-newest/>`__. +This will allow you to translate via the web interface, and to use shared +automatically updated source files. + +This is best done with a workflow that periodically checks for translations. +An example with instructions can be found in the +`python-docs-tx-automations documentation <https://python-docs-transifex-automation.readthedocs.io/workflows.html>`__. +An in-depth guide for manually doing this can also be found +in the same documentation's +`commands page <https://python-docs-transifex-automation.readthedocs.io/commands.html>`__. + +To be added as coordinators on Transifex for your language, open an issue +in the `tracker <https://github.com/python-docs-translations/transifex-automations/issues>`__. + + +Glossary +-------- + +Each translation team should have a way to store translations of terms to ensure +consistency. This is often done with a glossary. More information about the use +of glossaries can be found in the :ref:`translation-style-guide`. + + +Moving the repo to the ``python`` org +------------------------------------- + +This will allow you to plug your translation into docsbuild-scripts_, and it +will be found at ``docs.python.org/LANG/``, but not in the switcher. + +.. TODO Give a general milestone when this will be done. + +Adding to the language switcher +------------------------------- + +.. TODO Specify branch: https://github.com/python/devguide/issues/1586 + +Once the following resources have been fully translated: + +- ``bugs.po``, with proper links to the language repository issue tracker +- all files in the ``tutorial/`` folder +- ``library/functions.po``, the page documenting builtins + +the translation can be added to the language switcher. This can be done with a +pull request to docsbuild-scripts_, like `this commit <https://github.com/python/docsbuild-scripts/commit/e4a8aff9772738a63d0945042777d18c3d926930>`__ +if your translation was previously built but not in the switcher, or like +`this commit <https://github.com/python/docsbuild-scripts/commit/a601ce67c6c2f3be7fde3376d3e5d3851f19950b>`__ +if this is it's initial addition. + + +PEP 545 summary +=============== + +Here are the essential points of :PEP:`545`: + +- Each translation is assigned an appropriate lowercase + `IETF language tag <https://datatracker.ietf.org/doc/html/rfc5646.html>`__. + The tag may have an optional region subtag, joined with a dash. + For example, ``pt`` (Portuguese) or ``pt-br`` (Brazilian Portuguese). + +- Each translation is under CC0 and is marked as such in the README. + +- Translation files are hosted in repositories under the Python org: + ``https://github.com/python/python-docs-{LANGUAGE_TAG}`` + +- Translations having completed ``bugs``, ``tutorial/`` + and ``library/functions`` are added to the language switcher. + + +Translating Sphinx +================== + +Some messages that appear in the docs must be translated in the +`Sphinx project <https://www.sphinx-doc.org/en/master/internals/contributing.html#translations>`__ +(`sphinx-doc on Transifex <https://app.transifex.com/sphinx-doc/>`__) or in +the :ref:`Python Docs Sphinx Theme <python-docs-theme-i18n>`. +Coordinators should direct some translators there, so that the documentation +is fully translated. + + +Coordination FAQ +================ + +Are there tools to help in managing the repo? +--------------------------------------------- + +Here's what we're using: + +- :pypi:`poutils` which includes: + + - :pypi:`pomerge` to propagate translations from one file to others. + - :pypi:`pospell` to check for typos in ``.po`` files. + - :pypi:`powrap` to rewrap the ``.po`` files + before committing. This helps keep Git diffs short. + - :pypi:`potodo` to list what needs to be translated. + +- :pypi:`sphinx-lint` to validate reST syntax in translation files. + +More related tools and projects can be found in the +`python-docs-translations`__ organisation on GitHub. + +__ https://github.com/python-docs-translations + + +How should I test my translation? +--------------------------------- + +Testing should ideally be set up in your repository, and will help catch errors +early and ensure translation quality. Testing generally consists of building, and +linting with :pypi:`sphinx-lint`. + +See `this documentation <https://python-docs-transifex-automation.readthedocs.io/workflows.html#test-build-workflow>`__ +for sample workflows with usage guides. + +The `dashboard <https://translations.python.org/build-details.html>`__ +also tests translations and uploads error logs. + + +How is a coordination team chosen? +---------------------------------- + +Each translation team will decide on the number of coordinators. +We recommend two or three coordinators, though you may begin with one. + +- Coordinator requests are to be public in the `translations category of the + Python Discourse <trans_disc_>`_. +- If the given language has a native core team member, they have input + on the coordinator request. +- Anyone who wants to become coordinator for their native language and shows + motivation by translating and building a community will be named + coordinator. +- We expect the local community to self-organize coordinators and contributors. + If you have questions, please ask on the mailing list or Discourse. +- If a coordinator becomes inactive or unreachable for a long + period of time, someone else can ask to be added as a primary coordinator in + the `translations category of the Python Discourse <trans_disc_>`_. + As a community resource, we aim to keep translations up to date with active + contributors, including coordinators. + + +I have a translation, but it's not in Git. What should I do? +------------------------------------------------------------ + +You can ask for help in one of the :ref:`translation-help`, and +the team will help you create an appropriate repository. You can still use tools +like Transifex, if you like. + + +My Git hierarchy does not match yours. Can I keep it? +----------------------------------------------------- + +No, inside the ``github.com/python`` organization all repositories must have the +exact same hierarchy so bots will be able to build all of our +translations. So, you may have to convert from one hierarchy to another. +Ask for help in one of the :ref:`translation-help` if you’re not sure on how to +do it. + + +What hierarchy should I use in my GitHub repository? +---------------------------------------------------- + +As for every project, we have a *branch* per version. We store ``.po`` +files in the root of the repository using the ``gettext_compact=0`` +style. + + +Which version of the Python documentation should be translated? +--------------------------------------------------------------- + +It's best to work on Python's current stable or beta version. You can then +propagate your translation from one branch to another using :pypi:`pomerge`. + + +The entry for my translation is missing or not up to date +--------------------------------------------------------- + +Make a PR on the `devguide <https://github.com/python/devguide/>`__ to update it. + + +How are translations built? +--------------------------- + +Translations are built by `docsbuild-scripts <https://github.com/python/docsbuild-scripts/>`__ +and hosted on docs.python.org. + + +Is there a Weblate instance we can translate on? +------------------------------------------------ + +There is currently no Weblate instance for Python translations. +See this `Discourse thread <https://discuss.python.org/t/docs-translation-platform/29940>`__ +for updates. + + +.. _EB: https://python.github.io/editorial-board/ +.. _trans_disc: https://discuss.python.org/c/documentation/translations/ +.. _docsbuild-scripts: https://github.com/python/docsbuild-scripts diff --git a/documentation/translations/index.rst b/documentation/translations/index.rst new file mode 100644 index 0000000000..a6d4dc4e72 --- /dev/null +++ b/documentation/translations/index.rst @@ -0,0 +1,9 @@ +============ +Translations +============ + +.. toctree:: + :maxdepth: 4 + + translating + coordinating diff --git a/documentation/translations/translating.rst b/documentation/translations/translating.rst new file mode 100644 index 0000000000..2e4f6cf91c --- /dev/null +++ b/documentation/translations/translating.rst @@ -0,0 +1,365 @@ +.. _translating: + +=========== +Translating +=========== + +.. highlight:: rest + +There are several documentation translations already +in production and can be found in the language switcher; others are works in +progress. To get started read your repository's contributing guide, which is +generally the ``README`` file, and this page. +If your language isn’t listed below, feel free to start the translation! +See :doc:`coordination <coordinating>` to get started. + +For more details about translations and their progress, see +`translations.python.org <https://translations.python.org>`__. + +.. _translation-coordinators: + +.. list-table:: + :header-rows: 1 + + * - Language + - Coordination team + - Links + * - Arabic (ar) + - Abdur-Rahmaan Janhangeer (:github-user:`Abdur-rahmaanJ`) + - :github:`GitHub <Abdur-rahmaanJ/python-docs-ar>` + * - `Bengali (bn-IN) <https://docs.python.org/bn-in/>`__ + - Kushal Das (:github-user:`kushaldas`) + - :github:`GitHub <python/python-docs-bn-in>` + * - `French (fr) <https://docs.python.org/fr/>`__ + - Julien Palard (:github-user:`JulienPalard`) + - `AFPy/python-docs-fr <https://git.afpy.org/AFPy/python-docs-fr/>`__, + :github:`mirror <python/python-docs-fr>` + * - `Greek (el) <https://docs.python.org/el/>`__ + - | Lysandros Nikolaou (:github-user:`lysnikolaou`), + | Fanis Petkos (:github-user:`thepetk`), + | Panagiotis Skias (:github-user:`skpanagiotis`) + - :github:`GitHub <python/python-docs-el>` + * - Hindi (hi-IN) + - Sanyam Khurana (:github-user:`CuriousLearner`) + - :github:`GitHub <CuriousLearner/python-docs-hi-in>` + * - Hungarian (hu) + - + - :github:`GitHub <python/python-docs-hu>` + * - `Indonesian (id) <https://docs.python.org/id/>`__ + - | Irvan Putra (:github-user:`irvan-putra`), + | Jeff Jacobson (:github-user:`jwjacobson`), + | Lutfi Zuchri (:github-user:`lutfizuchri`) + - :github:`GitHub <python/python-docs-id>` + * - `Italian (it) <https://docs.python.org/it/>`__ + - Alessandro Cucci (:github-user:`acuccie3`, `email <mailto:alessandro.cucci@gmail.com>`__) + - :github:`GitHub <python/python-docs-it>`, + `original announcement <https://mail.python.org/pipermail/doc-sig/2019-April/004114.html>`__ + * - `Japanese (ja) <https://docs.python.org/ja/>`__ + - | Kinebuchi Tomohiko (:github-user:`cocoatomo`), + | Atsuo Ishimoto (:github-user:`atsuoishimoto`) + - :github:`GitHub <python/python-docs-ja>` + * - `Korean (ko) <https://docs.python.org/ko/>`__ + - 오동권 (:github-user:`flowdas`) + - :github:`GitHub <python/python-docs-ko>` + * - Marathi (mr) + - Sanket Garade (:github-user:`sanketgarade`, `email <mailto:garade@pm.me>`__) + - :github:`GitHub <sanketgarade/python-doc-mr>` + * - Lithuanian (lt) + - Albertas Gimbutas (:github-user:`albertas`, `email <mailto:albertasgim@gmail.com>`__) + - `original announcement <https://mail.python.org/pipermail/doc-sig/2019-July/004138.html>`__ + * - Persian (fa) + - Alireza Shabani (:github-user:`revisto`) + - :github:`GitHub <revisto/python-docs-fa>` + * - `Polish (pl) <https://docs.python.org/pl/>`__ + - | Maciej Olko (:github-user:`m-aciek`), + | Stan Ulbrych (:github-user:`StanFromIreland`) + - :github:`GitHub <python/python-docs-pl>`, + `Transifex <tx_>`_, + `original announcement <https://mail.python.org/pipermail/doc-sig/2019-April/004106.html>`__ + * - `Brazilian Portuguese (pt-br) <https://docs.python.org/pt-br/>`__ + - | Rafael Fontenelle (:github-user:`rffontenelle`), + | Marco Rougeth (:github-user:`rougeth`) + - :github:`GitHub <python/python-docs-pt-br>`, + `guide <https://python.org.br/traducao/>`__, + `Telegram <https://t.me/pybr_i18n>`__, + `article <https://rgth.co/blog/python-ptbr-cenario-atual/>`__ + * - `Romanian (ro) <https://docs.python.org/ro/>`__ + - Octavian Mustafa (:github-user:`octaG-M`, `email <mailto:octawian@yahoo.com>`__) + - :github:`GitHub <python/python-docs-ro>` + * - Russian (ru) + - Daniil Kolesnikov (:github-user:`MLGRussianXP`, `email <mailto:mlgrussianxp@gmail.com>`__) + - :github:`GitHub <MLGRussianXP/python-docs-ru>`, + `original announcement <https://mail.python.org/pipermail/doc-sig/2019-May/004131.html>`__ + * - `Simplified Chinese (zh-cn) <https://docs.python.org/zh-cn/>`__ + - | Shengjing Zhu (:github-user:`zhsj`), + | Du, Meng (:github-user:`dumeng`) + - :github:`GitHub <python/python-docs-zh-cn>`, + `Transifex <tx_>`_ + * - `Spanish (es) <https://docs.python.org/es/>`__ + - Raúl Cumplido (:github-user:`raulcd`) + - :github:`GitHub <python/python-docs-es>` + * - Swedish (sv) + - Daniel Nylander (:github-user:`yeager`) + - :github:`GitHub <python/python-docs-sv>` + * - `Traditional Chinese (zh-tw) <https://docs.python.org/zh-tw/>`__ + - | 王威翔 Matt Wang (:github-user:`mattwang44`), + | Josix Wang (:github-user:`josix`) + - :github:`GitHub <python/python-docs-zh-tw>` + * - `Turkish (tr) <https://docs.python.org/tr/>`__ + - Ege Akman (:github-user:`egeakman`) + - :github:`GitHub <python/python-docs-tr>`, + `RTD <https://python-docs-tr.readthedocs.io/>`__ + * - `Ukrainian (uk) <https://docs.python.org/uk/>`__ + - Dmytro Kazanzhy (:github-user:`kazanzhy`, `email <mailto:dkazanzhy@gmail.com>`__) + - :github:`GitHub <python/python-docs-uk>`, + `Transifex <tx_>`_ + + +How to get help +=============== + +If there is already a repository for your language team (there may be links to +Telegrams/Discords in the ``README``), join and introduce +yourself. Your fellow translators will be more than happy to help! +General discussions about translations occur on the Python Docs Discord +`#translations channel <https://discord.gg/h3qDwgyzga>`__ and the +`translations category <discourse_>`_ of the Python Discourse. + +.. _translation-style-guide: + +Style guide +=========== + +Before translating, you should familiarize yourself with the general +documentation :doc:`style guide <../style-guide>`. Some translation-specific +guidelines are explained below. + + +Translate the meaning +--------------------- + +Try to stay as close as possible to the original text. Focus on translating its +meaning in the best possible way. + + +Gender neutrality +----------------- + +Many languages use grammatical gender. When possible and natural, prefer +gender-neutral or inclusive forms. Aim to reflect the inclusive tone of +the English documentation. + + +Roles and links +--------------- + +The Python docs contain many roles (``:role:`target```) that link to other parts +of the documentation. +Do not translate reStructuredText roles targets, such as ``:func:`print``` or +``:ref:`some-section``` because it will break the link. +If alternate text (``:role:`text <target>```) is provided, it generally +should be translated. You can also introduce alternate text for translation if +the target is not a name or term. + +Links (```text <target>`_``) should be handled similarly. If possible, the target +should be updated to match the language. + +.. seealso:: + :doc:`../markup` + + +Translation quality +------------------- + +Translators should know both English and the language they are +translating to. Translators should aim for a similar level of quality as that +of the English documentation. + +Do not rely solely on machine translation. These tools can be useful to speed up +work, but often produce inaccurate or misleading results and should be reviewed +by a human. + + +Terminology +----------- + +The documentation is full of technical terms, some are common in general +programming and have translations, whereas others are specific to Python +and previous translations are not available. +Translation teams should keep the translations of these terms +consistent, which is done with glossaries. + +Some general guidelines for deciding on a translation: + +- Use existing community conventions over inventing new terms. +- You can use a hybrid English form if users are generally familiar + with the English word. +- For common terms, the English word may be best. +- Use other translations as a reference as to what they did for the word. +- Be careful to not translate names. +- Use your best judgment. +- When you translate a specific term, record it in your translations glossary to + help fellow translators and ensure consistency. + + +Dialects +-------- + +Some translations receive contributions from people of several different dialects, +understandably the language will differ. It is recommended however that +translators try to keep files and sections consistent. + + +Code examples +------------- + +Translate values in code examples, that is string literals, and comments. +Don't translate keywords or names, including variable, function, class, argument, +and attribute names. An example of a translated codeblock from the `tutorial <https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments>`__ +is provided below: + +.. code-block:: python + + def cheeseshop(kind, *arguments, **keywords): + print("-- Czy jest może", kind, "?") + print("-- Przykro mi, nie mamy już sera", kind) + for arg in arguments: + print(arg) + print("-" * 40) + for kw in keywords: + print(kw, ":", keywords[kw]) + + +.. _transifex-use: + +Transifex +========= + +.. important:: + + There are many translations in the `python-doc organization on Transifex <tx_>`_, + some of which, however, are not used or do not have a coordination team. + Confirm that a coordination team exists before you begin translating. + +Several language projects use Transifex as their translation interface. +Translations on Transifex are carried out via a web interface, similar to Weblate. +You should translate the `python-newest <tx_>`_ project. +If you are new to Transifex, it is recommended that you take the time to read +through the following resources from the Transifex documentation: + +- `Getting started as a translator <https://help.transifex.com/en/articles/6248698-getting-started-as-a-translator>`__: + This covers signing up for an account and joining a translation team. +- `Translating with the Web Editor <https://help.transifex.com/en/articles/6318216-translating-with-the-web-editor>`__: + This covers getting to the editor, searching and filtering strings, and translating strings. +- `Other Tools in the Editor <https://help.transifex.com/en/articles/6318944-other-tools-in-the-editor>`__: + This covers the history, glossary, comments, keyboard shortcuts, and more. +- `Starting with the basics <https://help.transifex.com/en/collections/3441044-starting-with-the-basics>`__: + A group of documents with basic information. + +Within the organization, a project for translating the +:github:`Python Docs Sphinx Theme <python/python-docs-theme>` can also be +found. +For further information about Transifex see our `documentation <https://python-docs-transifex-automation.readthedocs.io/>`__. + + +Resources +========= + +Some useful resources: + +- :ref:`git-boot-camp`: + Several translations accept contributions by pull requests. Most have their + own guide for how to do this, but this can provide useful tips. +- `Translation issues & improvements <https://github.com/orgs/python/projects/58>`__ GitHub project: + This project contains issues and pull requests that aim to improve + the Python documentation for translations. +- `Python Pootle archive <https://github.com/python/pootle-python-org-backup>`__: + Pootle is no longer used for translation. Contains translations for old Python versions. + + +Translation FAQ +=============== + +.. _docs-build-translation: + +How do I build a docs translation? +---------------------------------- + +To build a documentation translation for a specific language, +you need to have Python installed and a +local copy of the :github:`CPython repository <python/cpython>` and +translation repository (see table above). The PO files must be placed +in a :samp:`locales/{LANG}/LC_MESSAGES/` (replacing :samp:`{LANG}` with the translation's +language code) folder inside the :file:`Doc/` directory of the CPython repository. + +You can then build with :ref:`make <doc-build-make>` by adding +a ``SPHINXOPTS="-D language=LANG"`` variable before the target +or by using :ref:`Sphinx directly <doc-build-sphinx>` and adding a +``-D language=LANG`` option. For example: + +.. code-block:: bash + + # Build the HTML format of the Polish translation using make + make SPHINXOPTS="-D language=pl" html + + # Build the HTML format of the Romanian translation using Sphinx directly + python -m sphinx -b html . build/html -D language=ro + + +Which version of the Python documentation should I work on? +----------------------------------------------------------- + +You should work on the latest branch available to you for translation (this should +be the latest non-alpha branch), the translations should then be propagated by +your languages coordination team. + + +.. _python-docs-theme-i18n: + +How do I translate the Python Docs Sphinx Theme? +------------------------------------------------ + +The Sphinx theme for the Python documentation supports localization. + +You can translate either on +`Transifex <https://explore.transifex.com/python-doc/python-docs-theme/>`__ +(see :ref:`translating on Transifex <transifex-use>` for more information) +or locally by following the steps outlined below. + +To translate locally, clone the :github:`Python Docs Sphinx Theme repository <python/python-docs-theme>` and run the following +commands to generate the PO files. Replace ``LANG`` with the same language code +that is used for the docs translation: + +.. code-block:: bash + + python babel_runner.py extract + python babel_runner.py init -l LANG + +The file can then be found at: + +.. code-block:: text + + python-docs-theme/locale/LANG/LC_MESSAGES/python-docs-theme.po + +After translating, submit your PO file via a pull request to the +:github:`repository <python/python-docs-theme>`. +See our :ref:`git-boot-camp` for more information about using Git. + +To update an existing translation after source changes, run: + +.. code-block:: bash + + python babel_runner.py update # To update source for all languages + python babel_runner.py update -l LANG # To update source just for LANG + + +The coordination team for my language is inactive, what do I do? +---------------------------------------------------------------- + +If you would like to coordinate, open a pull request in the +`devguide <https://github.com/python/devguide>`__ adding yourself to the table +at the top of this page, and ping ``@python/editorial-board``. + + +.. _discourse: https://discuss.python.org/c/documentation/translations/ +.. _tx: https://explore.transifex.com/python-doc/python-newest/ diff --git a/documentation/translations/translator-workload.svg b/documentation/translations/translator-workload.svg new file mode 100644 index 0000000000..e3e1318613 --- /dev/null +++ b/documentation/translations/translator-workload.svg @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="460.8pt" + height="345.6pt" + viewBox="0 0 460.8 345.6" + version="1.1" + id="svg18" + sodipodi:docname="translator-workload.svg" + inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <sodipodi:namedview + id="namedview18" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="pt" + inkscape:zoom="1.0864401" + inkscape:cx="282.57426" + inkscape:cy="148.19041" + inkscape:window-width="1712" + inkscape:window-height="894" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg18" /> + <metadata + id="metadata1"> + <rdf:RDF> + <cc:Work> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:date>2025-06-29T10:46:39.952440</dc:date> + <dc:format>image/svg+xml</dc:format> + <dc:creator> + <cc:Agent> + <dc:title>Matplotlib v3.10.3, https://matplotlib.org/</dc:title> + </cc:Agent> + </dc:creator> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs1"> + <style + type="text/css" + id="style1">*{stroke-linejoin: round; stroke-linecap: butt}</style> + </defs> + <g + id="figure_1"> + <g + id="patch_1"> + <path + d="M 0 345.6 L 1 345.631436 L 2 345.668377 L 3 345.766123 L 4 345.798645 L 5 345.87227 L 6 345.910835 L 7 345.946248 L 8 346.003888 L 9 346.074274 L 10 346.126239 L 11 346.185328 L 12 346.273649 L 13 346.319794 L 14 346.362205 L 15 346.392697 L 16 346.418742 L 17 346.439942 L 18 346.494243 L 19 346.522181 L 20 346.551905 L 21 346.5773 L 22 346.5885 L 23 346.598624 L 24 346.59842 L 25 346.58891 L 26 346.577256 L 27 346.546227 L 28 346.535059 L 29 346.504942 L 30 346.445165 L 31 346.407973 L 32 346.368877 L 33 346.326437 L 34 346.293672 L 35 346.226246 L 36 346.18712 L 37 346.144445 L 38 346.073865 L 39 346.037474 L 40 345.979071 L 41 345.868118 L 42 345.79746 L 43 345.68452 L 44 345.638747 L 45 345.577464 L 46 345.528965 L 47 345.448142 L 48 345.329623 L 49 345.259412 L 50 345.17615 L 51 345.143008 L 52 345.091771 L 53 345.023372 L 54 344.957157 L 55 344.88024 L 56 344.852924 L 57 344.826447 L 58 344.803796 L 59 344.784265 L 60 344.757871 L 61 344.7081 L 62 344.673027 L 63 344.637161 L 64 344.621794 L 65 344.606025 L 66 344.602612 L 67 344.600195 L 68 344.600681 L 69 344.60261 L 70 344.615867 L 71 344.624258 L 72 344.645794 L 73 344.668827 L 74 344.68606 L 75 344.704523 L 76 344.724975 L 77 344.741575 L 78 344.804354 L 79 344.879619 L 80 344.912258 L 81 344.979822 L 82 345.033869 L 83 345.067573 L 84 345.157699 L 85 345.186234 L 86 345.21772 L 87 345.248731 L 88 345.303539 L 89 345.368126 L 90 345.406322 L 91 345.502256 L 92 345.551514 L 93 345.595583 L 94 345.635707 L 95 345.744074 L 96 345.785702 L 97 345.847844 L 98 345.917806 L 99 346.02231 L 100 346.059298 L 101 346.105175 L 102 346.17367 L 103 346.222416 L 104 346.300013 L 105 346.330554 L 106 346.400068 L 107 346.424041 L 108 346.452663 L 109 346.494456 L 110 346.516032 L 111 346.52998 L 112 346.556702 L 113 346.566012 L 114 346.578459 L 115 346.589514 L 116 346.595178 L 117 346.599942 L 118 346.594394 L 119 346.581106 L 120 346.573589 L 121 346.548804 L 122 346.525235 L 123 346.489055 L 124 346.463093 L 125 346.440771 L 126 346.372011 L 127 346.297476 L 128 346.203497 L 129 346.152445 L 130 346.098511 L 131 346.06326 L 132 345.957172 L 133 345.904908 L 134 345.868001 L 135 345.83697 L 136 345.775815 L 137 345.708395 L 138 345.659489 L 139 345.594297 L 140 345.556109 L 141 345.514113 L 142 345.472096 L 143 345.41258 L 144 345.29942 L 145 345.247169 L 146 345.207751 L 147 345.16065 L 148 345.10387 L 149 345.071207 L 150 345.035029 L 151 345.002939 L 152 344.968659 L 153 344.910281 L 154 344.865096 L 155 344.835472 L 156 344.785086 L 157 344.759889 L 158 344.738838 L 159 344.70387 L 160 344.67958 L 161 344.665513 L 162 344.646571 L 163 344.63091 L 164 344.618358 L 165 344.612522 L 166 344.60564 L 167 344.600466 L 168 344.602249 L 169 344.604974 L 170 344.616128 L 171 344.644363 L 172 344.688151 L 173 344.70884 L 174 344.749813 L 175 344.789888 L 176 344.808998 L 177 344.831507 L 178 344.898158 L 179 344.947868 L 180 345.021574 L 181 345.052888 L 182 345.12951 L 183 345.167808 L 184 345.241925 L 185 345.345983 L 186 345.415814 L 187 345.521048 L 188 345.576063 L 189 345.699538 L 190 345.770097 L 191 345.885936 L 192 345.936117 L 193 345.971721 L 194 346.063128 L 195 346.116636 L 196 346.204544 L 197 346.273729 L 198 346.320493 L 199 346.392537 L 200 346.442679 L 201 346.460069 L 202 346.487072 L 203 346.506499 L 204 346.525837 L 205 346.564086 L 206 346.580519 L 207 346.588888 L 208 346.593207 L 209 346.599762 L 210 346.597216 L 211 346.591757 L 212 346.575329 L 213 346.543394 L 214 346.505414 L 215 346.47061 L 216 346.407538 L 217 346.386111 L 218 346.335493 L 219 346.310536 L 220 346.254902 L 221 346.223673 L 222 346.173529 L 223 346.141036 L 224 346.060624 L 225 345.991698 L 226 345.876001 L 227 345.800522 L 228 345.684997 L 229 345.605513 L 230 345.497072 L 231 345.457704 L 232 345.354836 L 233 345.255038 L 234 345.209541 L 235 345.175219 L 236 345.123263 L 237 345.083616 L 238 345.048102 L 239 344.980457 L 240 344.941375 L 241 344.890894 L 242 344.841588 L 243 344.790518 L 244 344.746279 L 245 344.724259 L 246 344.708703 L 247 344.666256 L 248 344.651388 L 249 344.62866 L 250 344.608344 L 251 344.602547 L 252 344.600065 L 253 344.603122 L 254 344.614718 L 255 344.631638 L 256 344.663299 L 257 344.677382 L 258 344.730054 L 259 344.779143 L 260 344.833844 L 261 344.878192 L 262 344.948184 L 263 344.998567 L 264 345.052474 L 265 345.121913 L 266 345.179301 L 267 345.229466 L 268 345.306628 L 269 345.364818 L 270 345.425456 L 271 345.462657 L 272 345.527749 L 273 345.632879 L 274 345.693181 L 275 345.789503 L 276 345.821506 L 277 345.872523 L 278 345.989315 L 279 346.024762 L 280 346.080642 L 281 346.111018 L 282 346.199404 L 283 346.244168 L 284 346.325056 L 285 346.385202 L 286 346.448288 L 287 346.471236 L 288 346.487406 L 289 346.516335 L 290 346.546687 L 291 346.559261 L 292 346.58414 L 293 346.596224 L 294 346.599986 L 295 346.59555 L 296 346.583211 L 297 346.568798 L 298 346.552725 L 299 346.517204 L 300 346.49727 L 301 346.440681 L 302 346.373487 L 303 346.346117 L 304 346.311969 L 305 346.263289 L 306 346.215004 L 307 346.155927 L 308 346.060322 L 309 346.017182 L 310 345.967334 L 311 345.9088 L 312 345.861214 L 313 345.800086 L 314 345.744001 L 315 345.66983 L 316 345.552592 L 317 345.496868 L 318 345.388642 L 319 345.282492 L 320 345.17492 L 321 345.140412 L 322 345.037105 L 323 344.961381 L 324 344.921946 L 325 344.882562 L 326 344.86008 L 327 344.804267 L 328 344.778215 L 329 344.74798 L 330 344.697209 L 331 344.678558 L 332 344.656849 L 333 344.644203 L 334 344.62521 L 335 344.60782 L 336 344.600782 L 337 344.601806 L 338 344.60881 L 339 344.61818 L 340 344.641578 L 341 344.666661 L 342 344.67906 L 343 344.712153 L 344 344.72852 L 345 344.746925 L 346 344.796062 L 347 344.839875 L 348 344.88296 L 349 344.905901 L 350 344.946164 L 351 345.031024 L 352 345.073416 L 353 345.137802 L 354 345.182091 L 355 345.289937 L 356 345.366877 L 357 345.403319 L 358 345.458206 L 359 345.533307 L 360 345.591902 L 361 345.628477 L 362 345.740524 L 363 345.802209 L 364 345.852729 L 365 345.951514 L 366 345.989536 L 367 346.024984 L 368 346.116618 L 369 346.15989 L 370 346.213219 L 371 346.246084 L 372 346.308978 L 373 346.362832 L 374 346.419958 L 375 346.442048 L 376 346.485787 L 377 346.532881 L 378 346.549728 L 379 346.577802 L 380 346.588798 L 381 346.593367 L 382 346.599015 L 383 346.599066 L 384 346.595976 L 385 346.592463 L 386 346.586641 L 387 346.573789 L 388 346.550164 L 389 346.53528 L 390 346.511708 L 391 346.475389 L 392 346.443806 L 393 346.413913 L 394 346.335221 L 395 346.29867 L 396 346.272947 L 397 346.202274 L 398 346.111172 L 399 346.049215 L 400 346.015602 L 401 345.981102 L 402 345.883662 L 403 345.836072 L 404 345.804566 L 405 345.760881 L 406 345.690712 L 407 345.640845 L 408 345.606168 L 409 345.49652 L 410 345.463049 L 411 345.425707 L 412 345.345462 L 413 345.306968 L 414 345.265191 L 415 345.222766 L 416 345.113038 L 417 345.024753 L 418 344.950107 L 419 344.86165 L 420 344.787588 L 421 344.738423 L 422 344.682806 L 423 344.648106 L 424 344.636235 L 425 344.614012 L 426 344.602033 L 427 344.600281 L 428 344.605698 L 429 344.621896 L 430 344.638396 L 431 344.669579 L 432 344.682944 L 433 344.712587 L 434 344.77561 L 435 344.824931 L 436 344.87102 L 437 344.953247 L 438 344.99915 L 439 345.033475 L 440 345.087014 L 441 345.175901 L 442 345.207039 L 443 345.315088 L 444 345.42716 L 445 345.462598 L 446 345.547384 L 447 345.612991 L 448 345.715045 L 449 345.83126 L 450 345.871951 L 451 345.91304 L 452 345.949681 L 453 345.990677 L 454 346.066746 L 455 346.142812 L 456 346.1735 L 457 346.199991 L 458 346.256572 L 459 346.301088 L 460.8 346.331106 L 461.558162 344.6 L 461.600727 343.6 L 461.653592 342.6 L 461.684513 341.6 L 461.710788 340.6 L 461.725721 339.6 L 461.75601 338.6 L 461.777339 337.6 L 461.794228 336.6 L 461.798943 335.6 L 461.799553 334.6 L 461.797507 333.6 L 461.791646 332.6 L 461.772999 331.6 L 461.740942 330.6 L 461.694502 329.6 L 461.652556 328.6 L 461.585851 327.6 L 461.516785 326.6 L 461.46941 325.6 L 461.417891 324.6 L 461.378191 323.6 L 461.308771 322.6 L 461.24224 321.6 L 461.133331 320.6 L 461.068083 319.6 L 460.959875 318.6 L 460.898871 317.6 L 460.850186 316.6 L 460.773952 315.6 L 460.714421 314.6 L 460.639793 313.6 L 460.520966 312.6 L 460.423021 311.6 L 460.343973 310.6 L 460.298226 309.6 L 460.270954 308.6 L 460.227292 307.6 L 460.178708 306.6 L 460.146974 305.6 L 460.066744 304.6 L 460.000251 303.6 L 459.976226 302.6 L 459.915727 301.6 L 459.893495 300.6 L 459.874895 299.6 L 459.845569 298.6 L 459.829868 297.6 L 459.821569 296.6 L 459.811333 295.6 L 459.80099 294.6 L 459.801668 293.6 L 459.805448 292.6 L 459.821889 291.6 L 459.834023 290.6 L 459.844618 289.6 L 459.875995 288.6 L 459.901768 287.6 L 459.933177 286.6 L 459.955986 285.6 L 459.97358 284.6 L 460.023392 283.6 L 460.071052 282.6 L 460.142761 281.6 L 460.198524 280.6 L 460.224722 279.6 L 460.25549 278.6 L 460.345248 277.6 L 460.430042 276.6 L 460.495636 275.6 L 460.541461 274.6 L 460.584458 273.6 L 460.645971 272.6 L 460.745796 271.6 L 460.790226 270.6 L 460.840276 269.6 L 460.962117 268.6 L 461.02181 267.6 L 461.053376 266.6 L 461.085719 265.6 L 461.140279 264.6 L 461.182779 263.6 L 461.234251 262.6 L 461.322636 261.6 L 461.356833 260.6 L 461.400767 259.6 L 461.46448 258.6 L 461.539677 257.6 L 461.568491 256.6 L 461.610695 255.6 L 461.65328 254.6 L 461.670172 253.6 L 461.692653 252.6 L 461.73499 251.6 L 461.76495 250.6 L 461.783583 249.6 L 461.793375 248.6 L 461.797138 247.6 L 461.799976 246.6 L 461.798227 245.6 L 461.788871 244.6 L 461.778174 243.6 L 461.768304 242.6 L 461.749446 241.6 L 461.719107 240.6 L 461.680716 239.6 L 461.62123 238.6 L 461.577941 237.6 L 461.517203 236.6 L 461.433129 235.6 L 461.384836 234.6 L 461.341259 233.6 L 461.314378 232.6 L 461.282448 231.6 L 461.215256 230.6 L 461.134435 229.6 L 461.05889 228.6 L 461.01516 227.6 L 460.935265 226.6 L 460.873786 225.6 L 460.810161 224.6 L 460.702912 223.6 L 460.584202 222.6 L 460.542296 221.6 L 460.499342 220.6 L 460.437143 219.6 L 460.407006 218.6 L 460.374488 217.6 L 460.322553 216.6 L 460.217003 215.6 L 460.168557 214.6 L 460.122233 213.6 L 460.088417 212.6 L 460.04054 211.6 L 459.985662 210.6 L 459.961751 209.6 L 459.935714 208.6 L 459.879597 207.6 L 459.865723 206.6 L 459.839689 205.6 L 459.812943 204.6 L 459.805197 203.6 L 459.800044 202.6 L 459.806242 201.6 L 459.812549 200.6 L 459.82013 199.6 L 459.847636 198.6 L 459.891869 197.6 L 459.921407 196.6 L 459.963254 195.6 L 460.022428 194.6 L 460.045138 193.6 L 460.08177 192.6 L 460.138558 191.6 L 460.163728 190.6 L 460.246424 189.6 L 460.333356 188.6 L 460.38404 187.6 L 460.421434 186.6 L 460.505814 185.6 L 460.540325 184.6 L 460.632316 183.6 L 460.719341 182.6 L 460.842481 181.6 L 460.88035 180.6 L 460.927825 179.6 L 461.033351 178.6 L 461.130812 177.6 L 461.207449 176.6 L 461.239376 175.6 L 461.293616 174.6 L 461.332467 173.6 L 461.406172 172.6 L 461.438168 171.6 L 461.494707 170.6 L 461.530823 169.6 L 461.599425 168.6 L 461.630841 167.6 L 461.685508 166.6 L 461.704279 165.6 L 461.749908 164.6 L 461.772811 163.6 L 461.781352 162.6 L 461.788693 161.6 L 461.794988 160.6 L 461.798165 159.6 L 461.799751 158.6 L 461.798288 157.6 L 461.785334 156.6 L 461.770712 155.6 L 461.758856 154.6 L 461.740831 153.6 L 461.720453 152.6 L 461.697054 151.6 L 461.682145 150.6 L 461.627431 149.6 L 461.593834 148.6 L 461.531138 147.6 L 461.503763 146.6 L 461.459783 145.6 L 461.380836 144.6 L 461.323308 143.6 L 461.273329 142.6 L 461.201345 141.6 L 461.164813 140.6 L 461.0965 139.6 L 461.008294 138.6 L 460.886947 137.6 L 460.821266 136.6 L 460.787648 135.6 L 460.723371 134.6 L 460.6774 133.6 L 460.605243 132.6 L 460.565417 131.6 L 460.522787 130.6 L 460.416828 129.6 L 460.364043 128.6 L 460.284766 127.6 L 460.242362 126.6 L 460.210096 125.6 L 460.17523 124.6 L 460.132572 123.6 L 460.100999 122.6 L 460.03342 121.6 L 459.996535 120.6 L 459.968579 119.6 L 459.947731 118.6 L 459.922118 117.6 L 459.8845 116.6 L 459.869658 115.6 L 459.844928 114.6 L 459.826698 113.6 L 459.815291 112.6 L 459.809656 111.6 L 459.804902 110.6 L 459.800293 109.6 L 459.801966 108.6 L 459.807748 107.6 L 459.827744 106.6 L 459.839396 105.6 L 459.850385 104.6 L 459.863352 103.6 L 459.913766 102.6 L 459.934588 101.6 L 459.962535 100.6 L 460.01928 99.6 L 460.041924 98.6 L 460.093327 97.6 L 460.134463 96.6 L 460.217232 95.6 L 460.265692 94.6 L 460.317119 93.6 L 460.368279 92.6 L 460.435578 91.6 L 460.468732 90.6 L 460.53479 89.6 L 460.590975 88.6 L 460.652254 87.6 L 460.692237 86.6 L 460.78866 85.6 L 460.90042 84.6 L 460.939339 83.6 L 461.037188 82.6 L 461.071842 81.6 L 461.155524 80.6 L 461.20603 79.6 L 461.275073 78.6 L 461.376176 77.6 L 461.428622 76.6 L 461.51793 75.6 L 461.582938 74.6 L 461.624483 73.6 L 461.666823 72.6 L 461.688843 71.6 L 461.72633 70.6 L 461.743582 69.6 L 461.76699 68.6 L 461.775557 67.6 L 461.784646 66.6 L 461.791714 65.6 L 461.798741 64.6 L 461.799849 63.6 L 461.799863 62.6 L 461.797189 61.6 L 461.794163 60.6 L 461.788696 59.6 L 461.768701 58.6 L 461.75673 57.6 L 461.729611 56.6 L 461.702599 55.6 L 461.675433 54.6 L 461.620958 53.6 L 461.591342 52.6 L 461.549586 51.6 L 461.476477 50.6 L 461.433039 49.6 L 461.362348 48.6 L 461.323941 47.6 L 461.263602 46.6 L 461.232847 45.6 L 461.202349 44.6 L 461.143439 43.6 L 461.100262 42.6 L 461.05865 41.6 L 461.009535 40.6 L 460.944448 39.6 L 460.878053 38.6 L 460.75329 37.6 L 460.709475 36.6 L 460.655147 35.6 L 460.548443 34.6 L 460.505943 33.6 L 460.468449 32.6 L 460.378953 31.6 L 460.32173 30.6 L 460.252087 29.6 L 460.203068 28.6 L 460.147123 27.6 L 460.099998 26.6 L 460.06111 25.6 L 460.007418 24.6 L 459.961847 23.6 L 459.92491 22.6 L 459.902834 21.6 L 459.869951 20.6 L 459.840231 19.6 L 459.827681 18.6 L 459.815782 17.6 L 459.810664 16.6 L 459.802775 15.6 L 459.800144 14.6 L 459.800942 13.6 L 459.804183 12.6 L 459.819321 11.6 L 459.826258 10.6 L 459.842635 9.6 L 459.861048 8.6 L 459.89064 7.6 L 459.912722 6.6 L 459.970416 5.6 L 459.995607 4.6 L 460.06392 3.6 L 460.111046 2.6 L 460.148394 1.6 L 460.203603 0 L 459.8 0.506966 L 458.8 0.403856 L 457.8 0.349882 L 456.8 0.319162 L 455.8 0.263621 L 454.8 0.225886 L 453.8 0.157632 L 452.8 0.121803 L 451.8 0.052019 L 450.8 -0.007275 L 449.8 -0.045882 L 448.8 -0.079878 L 447.8 -0.122458 L 446.8 -0.169107 L 445.8 -0.223673 L 444.8 -0.309574 L 443.8 -0.35625 L 442.8 -0.413565 L 441.8 -0.443979 L 440.8 -0.52903 L 439.8 -0.562705 L 438.8 -0.650629 L 437.8 -0.705614 L 436.8 -0.744303 L 435.8 -0.814334 L 434.8 -0.84478 L 433.8 -0.902505 L 432.8 -0.919649 L 431.8 -0.944384 L 430.8 -0.959884 L 429.8 -0.983336 L 428.8 -0.99015 L 427.8 -0.994083 L 426.8 -0.997815 L 425.8 -0.999848 L 424.8 -0.991462 L 423.8 -0.975076 L 422.8 -0.948806 L 421.8 -0.935477 L 420.8 -0.905523 L 419.8 -0.871272 L 418.8 -0.850602 L 417.8 -0.80959 L 416.8 -0.736272 L 415.8 -0.713054 L 414.8 -0.672688 L 413.8 -0.645437 L 412.8 -0.564899 L 411.8 -0.511421 L 410.8 -0.43285 L 409.8 -0.384382 L 408.8 -0.270352 L 407.8 -0.169667 L 406.8 -0.085243 L 405.8 0.006297 L 404.8 0.10871 L 403.8 0.149518 L 402.8 0.192661 L 401.8 0.231962 L 400.8 0.265385 L 399.8 0.308493 L 398.8 0.414072 L 397.8 0.469773 L 396.8 0.5751 L 395.8 0.672097 L 394.8 0.695117 L 393.8 0.722104 L 392.8 0.752205 L 391.8 0.825447 L 390.8 0.862839 L 389.8 0.897798 L 388.8 0.916374 L 387.8 0.94688 L 386.8 0.959092 L 385.8 0.968868 L 384.8 0.978437 L 383.8 0.986646 L 382.8 0.997922 L 381.8 0.999784 L 380.8 0.993482 L 379.8 0.987469 L 378.8 0.982012 L 377.8 0.96182 L 376.8 0.951931 L 375.8 0.924178 L 374.8 0.905171 L 373.8 0.889772 L 372.8 0.860507 L 371.8 0.796703 L 370.8 0.74765 L 369.8 0.677461 L 368.8 0.648352 L 367.8 0.588782 L 366.8 0.541833 L 365.8 0.490711 L 364.8 0.436658 L 363.8 0.354971 L 362.8 0.276314 L 361.8 0.239654 L 360.8 0.118 L 359.8 0.039058 L 358.8 -0.025433 L 357.8 -0.071061 L 356.8 -0.18671 L 355.8 -0.234985 L 354.8 -0.270508 L 353.8 -0.314086 L 352.8 -0.349862 L 351.8 -0.420687 L 350.8 -0.457091 L 349.8 -0.554567 L 348.8 -0.623631 L 347.8 -0.689597 L 346.8 -0.754127 L 345.8 -0.777549 L 344.8 -0.804954 L 343.8 -0.853448 L 342.8 -0.883441 L 341.8 -0.915979 L 340.8 -0.930722 L 339.8 -0.944262 L 338.8 -0.967697 L 337.8 -0.980177 L 336.8 -0.987315 L 335.8 -0.992913 L 334.8 -0.998519 L 333.8 -1 L 332.8 -0.994007 L 331.8 -0.988042 L 330.8 -0.97653 L 329.8 -0.952723 L 328.8 -0.94259 L 327.8 -0.900632 L 326.8 -0.85856 L 325.8 -0.827344 L 324.8 -0.757486 L 323.8 -0.71323 L 322.8 -0.63076 L 321.8 -0.542573 L 320.8 -0.497653 L 319.8 -0.401923 L 318.8 -0.329819 L 317.8 -0.234829 L 316.8 -0.178455 L 315.8 -0.134258 L 314.8 -0.078442 L 313.8 -0.038504 L 312.8 0.036947 L 311.8 0.094942 L 310.8 0.132129 L 309.8 0.190656 L 308.8 0.293433 L 307.8 0.35016 L 306.8 0.421165 L 305.8 0.482934 L 304.8 0.520397 L 303.8 0.555683 L 302.8 0.599101 L 301.8 0.64096 L 300.8 0.668583 L 299.8 0.719698 L 298.8 0.753234 L 297.8 0.815297 L 296.8 0.834939 L 295.8 0.896712 L 294.8 0.919191 L 293.8 0.939414 L 292.8 0.960103 L 291.8 0.98653 L 290.8 0.997487 L 289.8 0.999269 L 288.8 0.996641 L 287.8 0.990091 L 286.8 0.968128 L 285.8 0.929128 L 284.8 0.908845 L 283.8 0.892196 L 282.8 0.830573 L 281.8 0.801989 L 280.8 0.778481 L 279.8 0.734033 L 278.8 0.70807 L 277.8 0.65771 L 276.8 0.581318 L 275.8 0.553797 L 274.8 0.521939 L 273.8 0.486315 L 272.8 0.398542 L 271.8 0.301531 L 270.8 0.221578 L 269.8 0.103903 L 268.8 0.031909 L 267.8 -0.072257 L 266.8 -0.183566 L 265.8 -0.278988 L 264.8 -0.373885 L 263.8 -0.440904 L 262.8 -0.501789 L 261.8 -0.54625 L 260.8 -0.581921 L 259.8 -0.661217 L 258.8 -0.691472 L 257.8 -0.765116 L 256.8 -0.797561 L 255.8 -0.842088 L 254.8 -0.863344 L 253.8 -0.891696 L 252.8 -0.920022 L 251.8 -0.954355 L 250.8 -0.967671 L 249.8 -0.984463 L 248.8 -0.995007 L 247.8 -0.998126 L 246.8 -0.999962 L 245.8 -0.994973 L 244.8 -0.989525 L 243.8 -0.97538 L 242.8 -0.940746 L 241.8 -0.921719 L 240.8 -0.879119 L 239.8 -0.861014 L 238.8 -0.816611 L 237.8 -0.794181 L 236.8 -0.753913 L 235.8 -0.721408 L 234.8 -0.658097 L 233.8 -0.569587 L 232.8 -0.483117 L 231.8 -0.403482 L 230.8 -0.349696 L 229.8 -0.289585 L 228.8 -0.218544 L 227.8 -0.098423 L 226.8 0.006039 L 225.8 0.116842 L 224.8 0.170115 L 223.8 0.243365 L 222.8 0.281948 L 221.8 0.357711 L 220.8 0.435272 L 219.8 0.521412 L 218.8 0.548855 L 217.8 0.644831 L 216.8 0.720941 L 215.8 0.771105 L 214.8 0.825458 L 213.8 0.853129 L 212.8 0.889151 L 211.8 0.920712 L 210.8 0.938819 L 209.8 0.955558 L 208.8 0.972565 L 207.8 0.989619 L 206.8 0.99403 L 205.8 0.998289 L 204.8 0.999886 L 203.8 0.998359 L 202.8 0.995935 L 201.8 0.992476 L 200.8 0.982211 L 199.8 0.962483 L 198.8 0.950784 L 197.8 0.90804 L 196.8 0.88236 L 195.8 0.838178 L 194.8 0.782063 L 193.8 0.725365 L 192.8 0.693505 L 191.8 0.656796 L 190.8 0.628663 L 189.8 0.572864 L 188.8 0.538147 L 187.8 0.46646 L 186.8 0.410402 L 185.8 0.328747 L 184.8 0.273173 L 183.8 0.188865 L 182.8 0.14624 L 181.8 0.055234 L 180.8 -0.005051 L 179.8 -0.110128 L 178.8 -0.174313 L 177.8 -0.253509 L 176.8 -0.319736 L 175.8 -0.374012 L 174.8 -0.407139 L 173.8 -0.463853 L 172.8 -0.50741 L 171.8 -0.604653 L 170.8 -0.678599 L 169.8 -0.740393 L 168.8 -0.768808 L 167.8 -0.794142 L 166.8 -0.860397 L 165.8 -0.903414 L 164.8 -0.931921 L 163.8 -0.943915 L 162.8 -0.957989 L 161.8 -0.968817 L 160.8 -0.984115 L 159.8 -0.993971 L 158.8 -0.999784 L 157.8 -0.998949 L 156.8 -0.996987 L 155.8 -0.993379 L 154.8 -0.976068 L 153.8 -0.966337 L 152.8 -0.932307 L 151.8 -0.907236 L 150.8 -0.868539 L 149.8 -0.802605 L 148.8 -0.761617 L 147.8 -0.686776 L 146.8 -0.654849 L 145.8 -0.630635 L 144.8 -0.604815 L 143.8 -0.545775 L 142.8 -0.491063 L 141.8 -0.384861 L 140.8 -0.304585 L 139.8 -0.187843 L 138.8 -0.08788 L 137.8 -0.035566 L 136.8 0.003007 L 135.8 0.039368 L 134.8 0.160354 L 133.8 0.191539 L 132.8 0.227915 L 131.8 0.290066 L 130.8 0.378077 L 129.8 0.42247 L 128.8 0.470988 L 127.8 0.569778 L 126.8 0.611246 L 125.8 0.653898 L 124.8 0.718748 L 123.8 0.785183 L 122.8 0.805272 L 121.8 0.829751 L 120.8 0.870359 L 119.8 0.894905 L 118.8 0.911852 L 117.8 0.942871 L 116.8 0.965923 L 115.8 0.985366 L 114.8 0.992773 L 113.8 0.996995 L 112.8 0.999656 L 111.8 0.999239 L 110.8 0.993894 L 109.8 0.984738 L 108.8 0.972213 L 107.8 0.945446 L 106.8 0.91655 L 105.8 0.86624 L 104.8 0.837897 L 103.8 0.782994 L 102.8 0.745187 L 101.8 0.692498 L 100.8 0.662794 L 99.8 0.631793 L 98.8 0.601321 L 97.8 0.559084 L 96.8 0.531062 L 95.8 0.433515 L 94.8 0.35707 L 93.8 0.301773 L 92.8 0.220903 L 91.8 0.143522 L 90.8 0.062112 L 89.8 0.005147 L 88.8 -0.117966 L 87.8 -0.149535 L 86.8 -0.216766 L 85.8 -0.295058 L 84.8 -0.387611 L 83.8 -0.421765 L 82.8 -0.452679 L 81.8 -0.503004 L 80.8 -0.547822 L 79.8 -0.588823 L 78.8 -0.618678 L 77.8 -0.663526 L 76.8 -0.74679 L 75.8 -0.76885 L 74.8 -0.812967 L 73.8 -0.833129 L 72.8 -0.893251 L 71.8 -0.93548 L 70.8 -0.958737 L 69.8 -0.976732 L 68.8 -0.983734 L 67.8 -0.995973 L 66.8 -0.999442 L 65.8 -0.998259 L 64.8 -0.994084 L 63.8 -0.980354 L 62.8 -0.972703 L 61.8 -0.958263 L 60.8 -0.927611 L 59.8 -0.902922 L 58.8 -0.882675 L 57.8 -0.864202 L 56.8 -0.845248 L 55.8 -0.810642 L 54.8 -0.743359 L 53.8 -0.695131 L 52.8 -0.665749 L 51.8 -0.633906 L 50.8 -0.555682 L 49.8 -0.45647 L 48.8 -0.412576 L 47.8 -0.301816 L 46.8 -0.248043 L 45.8 -0.189835 L 44.8 -0.153658 L 43.8 -0.098867 L 42.8 -0.015916 L 41.8 0.031754 L 40.8 0.120599 L 39.8 0.168247 L 38.8 0.248469 L 37.8 0.337896 L 36.8 0.382122 L 35.8 0.441179 L 34.8 0.539628 L 33.8 0.57467 L 32.8 0.620434 L 31.8 0.673635 L 30.8 0.709483 L 29.8 0.751738 L 28.8 0.793097 L 27.8 0.820445 L 26.8 0.88147 L 25.8 0.904483 L 24.8 0.919261 L 23.8 0.934284 L 22.8 0.947208 L 21.8 0.979534 L 20.8 0.996802 L 19.8 0.999844 L 18.8 0.997823 L 17.8 0.99401 L 16.8 0.978994 L 15.8 0.970072 L 14.8 0.95778 L 13.8 0.929404 L 12.8 0.901094 L 11.8 0.866107 L 10.8 0.813717 L 9.8 0.765101 L 8.8 0.721134 L 7.8 0.682742 L 6.8 0.590438 L 5.8 0.563187 L 4.8 0.517238 L 3.8 0.475854 L 2.8 0.436431 L 1.8 0.377515 L 0 0.273593 L 0.227262 1 L 0.140289 2 L 0.091558 3 L 0.053928 4 L 0.017733 5 L -0.06793 6 L -0.161753 7 L -0.273189 8 L -0.360274 9 L -0.40709 10 L -0.463838 11 L -0.531601 12 L -0.573508 13 L -0.625352 14 L -0.650645 15 L -0.724163 16 L -0.770317 17 L -0.791479 18 L -0.851149 19 L -0.887991 20 L -0.917061 21 L -0.941292 22 L -0.951546 23 L -0.981839 24 L -0.994579 25 L -0.999784 26 L -0.999825 27 L -0.998417 28 L -0.992654 29 L -0.986301 30 L -0.967662 31 L -0.943214 32 L -0.912437 33 L -0.895086 34 L -0.880479 35 L -0.851999 36 L -0.833049 37 L -0.804776 38 L -0.736949 39 L -0.694852 40 L -0.659088 41 L -0.608192 42 L -0.546144 43 L -0.469078 44 L -0.390646 45 L -0.314256 46 L -0.272519 47 L -0.174586 48 L -0.104796 49 L -0.033939 50 L 0.084549 51 L 0.122597 52 L 0.158643 53 L 0.20132 54 L 0.299241 55 L 0.371531 56 L 0.414118 57 L 0.451421 58 L 0.546295 59 L 0.588994 60 L 0.621715 61 L 0.647784 62 L 0.677809 63 L 0.707013 64 L 0.742447 65 L 0.763133 66 L 0.785911 67 L 0.848282 68 L 0.876933 69 L 0.89743 70 L 0.932584 71 L 0.952705 72 L 0.963835 73 L 0.983785 74 L 0.997162 75 L 0.998974 76 L 0.993744 77 L 0.987133 78 L 0.961107 79 L 0.93948 80 L 0.917584 81 L 0.899066 82 L 0.868853 83 L 0.826455 84 L 0.799415 85 L 0.778893 86 L 0.743514 87 L 0.655618 88 L 0.618638 89 L 0.545793 90 L 0.443104 91 L 0.409892 92 L 0.309442 93 L 0.277702 94 L 0.234758 95 L 0.200953 96 L 0.120665 97 L 0.086322 98 L 0.0144 99 L -0.061467 100 L -0.117562 101 L -0.207304 102 L -0.24726 103 L -0.314957 104 L -0.42911 105 L -0.460269 106 L -0.525752 107 L -0.557786 108 L -0.642979 109 L -0.673037 110 L -0.719408 111 L -0.749116 112 L -0.778759 113 L -0.843855 114 L -0.877651 115 L -0.902804 116 L -0.918897 117 L -0.955058 118 L -0.973964 119 L -0.984187 120 L -0.992492 121 L -0.999215 122 L -0.996501 123 L -0.988797 124 L -0.971166 125 L -0.940938 126 L -0.912341 127 L -0.885031 128 L -0.825603 129 L -0.77009 130 L -0.688452 131 L -0.647196 132 L -0.60259 133 L -0.511042 134 L -0.430427 135 L -0.384469 136 L -0.292923 137 L -0.225967 138 L -0.179248 139 L -0.136118 140 L -0.077875 141 L -0.030604 142 L 0.026452 143 L 0.080989 144 L 0.196427 145 L 0.315576 146 L 0.370627 147 L 0.40698 148 L 0.502034 149 L 0.546466 150 L 0.575573 151 L 0.667237 152 L 0.714029 153 L 0.749742 154 L 0.795559 155 L 0.859505 156 L 0.892455 157 L 0.917515 158 L 0.933607 159 L 0.970088 160 L 0.979122 161 L 0.985274 162 L 0.990848 163 L 0.99806 164 L 0.99889 165 L 0.994277 166 L 0.981883 167 L 0.973583 168 L 0.937803 169 L 0.919049 170 L 0.901448 171 L 0.87707 172 L 0.844234 173 L 0.771924 174 L 0.735339 175 L 0.713128 176 L 0.683072 177 L 0.643552 178 L 0.614091 179 L 0.569454 180 L 0.500184 181 L 0.392301 182 L 0.355195 183 L 0.247165 184 L 0.140245 185 L 0.103559 186 L 0.051805 187 L -0.035129 188 L -0.106027 189 L -0.227181 190 L -0.260107 191 L -0.313632 192 L -0.359984 193 L -0.401339 194 L -0.450067 195 L -0.490327 196 L -0.533979 197 L -0.560575 198 L -0.651745 199 L -0.691652 200 L -0.720319 201 L -0.762616 202 L -0.811738 203 L -0.865675 204 L -0.918013 205 L -0.952001 206 L -0.967156 207 L -0.980387 208 L -0.992416 209 L -0.998222 210 L -0.99846 211 L -0.995029 212 L -0.978361 213 L -0.950969 214 L -0.910428 215 L -0.890133 216 L -0.872536 217 L -0.847806 218 L -0.794595 219 L -0.753623 220 L -0.693228 221 L -0.609661 222 L -0.563669 223 L -0.532753 224 L -0.502298 225 L -0.455614 226 L -0.387673 227 L -0.355756 228 L -0.30615 229 L -0.205734 230 L -0.170513 231 L -0.129026 232 L -0.0754 233 L -0.035334 234 L 0.07453 235 L 0.195709 236 L 0.233871 237 L 0.303602 238 L 0.362359 239 L 0.415477 240 L 0.479944 241 L 0.522985 242 L 0.587131 243 L 0.631929 244 L 0.71055 245 L 0.733761 246 L 0.756219 247 L 0.826066 248 L 0.846169 249 L 0.872053 250 L 0.895656 251 L 0.909427 252 L 0.933238 253 L 0.968289 254 L 0.987905 255 L 0.997925 256 L 0.999511 257 L 0.997397 258 L 0.994191 259 L 0.987806 260 L 0.972822 261 L 0.963505 262 L 0.943913 263 L 0.912031 264 L 0.858743 265 L 0.824485 266 L 0.803278 267 L 0.770858 268 L 0.745139 269 L 0.704247 270 L 0.679944 271 L 0.652386 272 L 0.613312 273 L 0.574818 274 L 0.521172 275 L 0.478431 276 L 0.446006 277 L 0.408082 278 L 0.378531 279 L 0.304491 280 L 0.26975 281 L 0.198648 282 L 0.140692 283 L 0.106477 284 L 0.001931 285 L -0.031948 286 L -0.139586 287 L -0.197401 288 L -0.263521 289 L -0.338446 290 L -0.397233 291 L -0.504686 292 L -0.600611 293 L -0.660743 294 L -0.694963 295 L -0.772666 296 L -0.810252 297 L -0.853431 298 L -0.881952 299 L -0.917155 300 L -0.941985 301 L -0.967909 302 L -0.983386 303 L -0.988682 304 L -0.999195 305 L -0.999894 306 L -0.998307 307 L -0.983759 308 L -0.976299 309 L -0.949036 310 L -0.904736 311 L -0.887316 312 L -0.847912 313 L -0.811558 314 L -0.773772 315 L -0.719976 316 L -0.6736 317 L -0.625248 318 L -0.57127 319 L -0.507815 320 L -0.41649 321 L -0.374633 322 L -0.343546 323 L -0.27172 324 L -0.238363 325 L -0.204546 326 L -0.16887 327 L -0.085534 328 L -0.053624 329 L 0.040791 330 L 0.163353 331 L 0.248217 332 L 0.307634 333 L 0.341295 334 L 0.436499 335 L 0.466063 336 L 0.500969 337 L 0.532344 338 L 0.629809 339 L 0.655764 340 L 0.706154 341 L 0.736458 342 L 0.792812 343 L 0.811609 344 L 0.857562 345.6 z " + style="fill: #ffffff; stroke: #ffffff; stroke-width: 4; stroke-linejoin: miter" + id="path1" /> + <path + d="M 0 345.6 L 1 345.631436 L 2 345.668377 L 3 345.766123 L 4 345.798645 L 5 345.87227 L 6 345.910835 L 7 345.946248 L 8 346.003888 L 9 346.074274 L 10 346.126239 L 11 346.185328 L 12 346.273649 L 13 346.319794 L 14 346.362205 L 15 346.392697 L 16 346.418742 L 17 346.439942 L 18 346.494243 L 19 346.522181 L 20 346.551905 L 21 346.5773 L 22 346.5885 L 23 346.598624 L 24 346.59842 L 25 346.58891 L 26 346.577256 L 27 346.546227 L 28 346.535059 L 29 346.504942 L 30 346.445165 L 31 346.407973 L 32 346.368877 L 33 346.326437 L 34 346.293672 L 35 346.226246 L 36 346.18712 L 37 346.144445 L 38 346.073865 L 39 346.037474 L 40 345.979071 L 41 345.868118 L 42 345.79746 L 43 345.68452 L 44 345.638747 L 45 345.577464 L 46 345.528965 L 47 345.448142 L 48 345.329623 L 49 345.259412 L 50 345.17615 L 51 345.143008 L 52 345.091771 L 53 345.023372 L 54 344.957157 L 55 344.88024 L 56 344.852924 L 57 344.826447 L 58 344.803796 L 59 344.784265 L 60 344.757871 L 61 344.7081 L 62 344.673027 L 63 344.637161 L 64 344.621794 L 65 344.606025 L 66 344.602612 L 67 344.600195 L 68 344.600681 L 69 344.60261 L 70 344.615867 L 71 344.624258 L 72 344.645794 L 73 344.668827 L 74 344.68606 L 75 344.704523 L 76 344.724975 L 77 344.741575 L 78 344.804354 L 79 344.879619 L 80 344.912258 L 81 344.979822 L 82 345.033869 L 83 345.067573 L 84 345.157699 L 85 345.186234 L 86 345.21772 L 87 345.248731 L 88 345.303539 L 89 345.368126 L 90 345.406322 L 91 345.502256 L 92 345.551514 L 93 345.595583 L 94 345.635707 L 95 345.744074 L 96 345.785702 L 97 345.847844 L 98 345.917806 L 99 346.02231 L 100 346.059298 L 101 346.105175 L 102 346.17367 L 103 346.222416 L 104 346.300013 L 105 346.330554 L 106 346.400068 L 107 346.424041 L 108 346.452663 L 109 346.494456 L 110 346.516032 L 111 346.52998 L 112 346.556702 L 113 346.566012 L 114 346.578459 L 115 346.589514 L 116 346.595178 L 117 346.599942 L 118 346.594394 L 119 346.581106 L 120 346.573589 L 121 346.548804 L 122 346.525235 L 123 346.489055 L 124 346.463093 L 125 346.440771 L 126 346.372011 L 127 346.297476 L 128 346.203497 L 129 346.152445 L 130 346.098511 L 131 346.06326 L 132 345.957172 L 133 345.904908 L 134 345.868001 L 135 345.83697 L 136 345.775815 L 137 345.708395 L 138 345.659489 L 139 345.594297 L 140 345.556109 L 141 345.514113 L 142 345.472096 L 143 345.41258 L 144 345.29942 L 145 345.247169 L 146 345.207751 L 147 345.16065 L 148 345.10387 L 149 345.071207 L 150 345.035029 L 151 345.002939 L 152 344.968659 L 153 344.910281 L 154 344.865096 L 155 344.835472 L 156 344.785086 L 157 344.759889 L 158 344.738838 L 159 344.70387 L 160 344.67958 L 161 344.665513 L 162 344.646571 L 163 344.63091 L 164 344.618358 L 165 344.612522 L 166 344.60564 L 167 344.600466 L 168 344.602249 L 169 344.604974 L 170 344.616128 L 171 344.644363 L 172 344.688151 L 173 344.70884 L 174 344.749813 L 175 344.789888 L 176 344.808998 L 177 344.831507 L 178 344.898158 L 179 344.947868 L 180 345.021574 L 181 345.052888 L 182 345.12951 L 183 345.167808 L 184 345.241925 L 185 345.345983 L 186 345.415814 L 187 345.521048 L 188 345.576063 L 189 345.699538 L 190 345.770097 L 191 345.885936 L 192 345.936117 L 193 345.971721 L 194 346.063128 L 195 346.116636 L 196 346.204544 L 197 346.273729 L 198 346.320493 L 199 346.392537 L 200 346.442679 L 201 346.460069 L 202 346.487072 L 203 346.506499 L 204 346.525837 L 205 346.564086 L 206 346.580519 L 207 346.588888 L 208 346.593207 L 209 346.599762 L 210 346.597216 L 211 346.591757 L 212 346.575329 L 213 346.543394 L 214 346.505414 L 215 346.47061 L 216 346.407538 L 217 346.386111 L 218 346.335493 L 219 346.310536 L 220 346.254902 L 221 346.223673 L 222 346.173529 L 223 346.141036 L 224 346.060624 L 225 345.991698 L 226 345.876001 L 227 345.800522 L 228 345.684997 L 229 345.605513 L 230 345.497072 L 231 345.457704 L 232 345.354836 L 233 345.255038 L 234 345.209541 L 235 345.175219 L 236 345.123263 L 237 345.083616 L 238 345.048102 L 239 344.980457 L 240 344.941375 L 241 344.890894 L 242 344.841588 L 243 344.790518 L 244 344.746279 L 245 344.724259 L 246 344.708703 L 247 344.666256 L 248 344.651388 L 249 344.62866 L 250 344.608344 L 251 344.602547 L 252 344.600065 L 253 344.603122 L 254 344.614718 L 255 344.631638 L 256 344.663299 L 257 344.677382 L 258 344.730054 L 259 344.779143 L 260 344.833844 L 261 344.878192 L 262 344.948184 L 263 344.998567 L 264 345.052474 L 265 345.121913 L 266 345.179301 L 267 345.229466 L 268 345.306628 L 269 345.364818 L 270 345.425456 L 271 345.462657 L 272 345.527749 L 273 345.632879 L 274 345.693181 L 275 345.789503 L 276 345.821506 L 277 345.872523 L 278 345.989315 L 279 346.024762 L 280 346.080642 L 281 346.111018 L 282 346.199404 L 283 346.244168 L 284 346.325056 L 285 346.385202 L 286 346.448288 L 287 346.471236 L 288 346.487406 L 289 346.516335 L 290 346.546687 L 291 346.559261 L 292 346.58414 L 293 346.596224 L 294 346.599986 L 295 346.59555 L 296 346.583211 L 297 346.568798 L 298 346.552725 L 299 346.517204 L 300 346.49727 L 301 346.440681 L 302 346.373487 L 303 346.346117 L 304 346.311969 L 305 346.263289 L 306 346.215004 L 307 346.155927 L 308 346.060322 L 309 346.017182 L 310 345.967334 L 311 345.9088 L 312 345.861214 L 313 345.800086 L 314 345.744001 L 315 345.66983 L 316 345.552592 L 317 345.496868 L 318 345.388642 L 319 345.282492 L 320 345.17492 L 321 345.140412 L 322 345.037105 L 323 344.961381 L 324 344.921946 L 325 344.882562 L 326 344.86008 L 327 344.804267 L 328 344.778215 L 329 344.74798 L 330 344.697209 L 331 344.678558 L 332 344.656849 L 333 344.644203 L 334 344.62521 L 335 344.60782 L 336 344.600782 L 337 344.601806 L 338 344.60881 L 339 344.61818 L 340 344.641578 L 341 344.666661 L 342 344.67906 L 343 344.712153 L 344 344.72852 L 345 344.746925 L 346 344.796062 L 347 344.839875 L 348 344.88296 L 349 344.905901 L 350 344.946164 L 351 345.031024 L 352 345.073416 L 353 345.137802 L 354 345.182091 L 355 345.289937 L 356 345.366877 L 357 345.403319 L 358 345.458206 L 359 345.533307 L 360 345.591902 L 361 345.628477 L 362 345.740524 L 363 345.802209 L 364 345.852729 L 365 345.951514 L 366 345.989536 L 367 346.024984 L 368 346.116618 L 369 346.15989 L 370 346.213219 L 371 346.246084 L 372 346.308978 L 373 346.362832 L 374 346.419958 L 375 346.442048 L 376 346.485787 L 377 346.532881 L 378 346.549728 L 379 346.577802 L 380 346.588798 L 381 346.593367 L 382 346.599015 L 383 346.599066 L 384 346.595976 L 385 346.592463 L 386 346.586641 L 387 346.573789 L 388 346.550164 L 389 346.53528 L 390 346.511708 L 391 346.475389 L 392 346.443806 L 393 346.413913 L 394 346.335221 L 395 346.29867 L 396 346.272947 L 397 346.202274 L 398 346.111172 L 399 346.049215 L 400 346.015602 L 401 345.981102 L 402 345.883662 L 403 345.836072 L 404 345.804566 L 405 345.760881 L 406 345.690712 L 407 345.640845 L 408 345.606168 L 409 345.49652 L 410 345.463049 L 411 345.425707 L 412 345.345462 L 413 345.306968 L 414 345.265191 L 415 345.222766 L 416 345.113038 L 417 345.024753 L 418 344.950107 L 419 344.86165 L 420 344.787588 L 421 344.738423 L 422 344.682806 L 423 344.648106 L 424 344.636235 L 425 344.614012 L 426 344.602033 L 427 344.600281 L 428 344.605698 L 429 344.621896 L 430 344.638396 L 431 344.669579 L 432 344.682944 L 433 344.712587 L 434 344.77561 L 435 344.824931 L 436 344.87102 L 437 344.953247 L 438 344.99915 L 439 345.033475 L 440 345.087014 L 441 345.175901 L 442 345.207039 L 443 345.315088 L 444 345.42716 L 445 345.462598 L 446 345.547384 L 447 345.612991 L 448 345.715045 L 449 345.83126 L 450 345.871951 L 451 345.91304 L 452 345.949681 L 453 345.990677 L 454 346.066746 L 455 346.142812 L 456 346.1735 L 457 346.199991 L 458 346.256572 L 459 346.301088 L 460.8 346.331106 L 461.558162 344.6 L 461.600727 343.6 L 461.653592 342.6 L 461.684513 341.6 L 461.710788 340.6 L 461.725721 339.6 L 461.75601 338.6 L 461.777339 337.6 L 461.794228 336.6 L 461.798943 335.6 L 461.799553 334.6 L 461.797507 333.6 L 461.791646 332.6 L 461.772999 331.6 L 461.740942 330.6 L 461.694502 329.6 L 461.652556 328.6 L 461.585851 327.6 L 461.516785 326.6 L 461.46941 325.6 L 461.417891 324.6 L 461.378191 323.6 L 461.308771 322.6 L 461.24224 321.6 L 461.133331 320.6 L 461.068083 319.6 L 460.959875 318.6 L 460.898871 317.6 L 460.850186 316.6 L 460.773952 315.6 L 460.714421 314.6 L 460.639793 313.6 L 460.520966 312.6 L 460.423021 311.6 L 460.343973 310.6 L 460.298226 309.6 L 460.270954 308.6 L 460.227292 307.6 L 460.178708 306.6 L 460.146974 305.6 L 460.066744 304.6 L 460.000251 303.6 L 459.976226 302.6 L 459.915727 301.6 L 459.893495 300.6 L 459.874895 299.6 L 459.845569 298.6 L 459.829868 297.6 L 459.821569 296.6 L 459.811333 295.6 L 459.80099 294.6 L 459.801668 293.6 L 459.805448 292.6 L 459.821889 291.6 L 459.834023 290.6 L 459.844618 289.6 L 459.875995 288.6 L 459.901768 287.6 L 459.933177 286.6 L 459.955986 285.6 L 459.97358 284.6 L 460.023392 283.6 L 460.071052 282.6 L 460.142761 281.6 L 460.198524 280.6 L 460.224722 279.6 L 460.25549 278.6 L 460.345248 277.6 L 460.430042 276.6 L 460.495636 275.6 L 460.541461 274.6 L 460.584458 273.6 L 460.645971 272.6 L 460.745796 271.6 L 460.790226 270.6 L 460.840276 269.6 L 460.962117 268.6 L 461.02181 267.6 L 461.053376 266.6 L 461.085719 265.6 L 461.140279 264.6 L 461.182779 263.6 L 461.234251 262.6 L 461.322636 261.6 L 461.356833 260.6 L 461.400767 259.6 L 461.46448 258.6 L 461.539677 257.6 L 461.568491 256.6 L 461.610695 255.6 L 461.65328 254.6 L 461.670172 253.6 L 461.692653 252.6 L 461.73499 251.6 L 461.76495 250.6 L 461.783583 249.6 L 461.793375 248.6 L 461.797138 247.6 L 461.799976 246.6 L 461.798227 245.6 L 461.788871 244.6 L 461.778174 243.6 L 461.768304 242.6 L 461.749446 241.6 L 461.719107 240.6 L 461.680716 239.6 L 461.62123 238.6 L 461.577941 237.6 L 461.517203 236.6 L 461.433129 235.6 L 461.384836 234.6 L 461.341259 233.6 L 461.314378 232.6 L 461.282448 231.6 L 461.215256 230.6 L 461.134435 229.6 L 461.05889 228.6 L 461.01516 227.6 L 460.935265 226.6 L 460.873786 225.6 L 460.810161 224.6 L 460.702912 223.6 L 460.584202 222.6 L 460.542296 221.6 L 460.499342 220.6 L 460.437143 219.6 L 460.407006 218.6 L 460.374488 217.6 L 460.322553 216.6 L 460.217003 215.6 L 460.168557 214.6 L 460.122233 213.6 L 460.088417 212.6 L 460.04054 211.6 L 459.985662 210.6 L 459.961751 209.6 L 459.935714 208.6 L 459.879597 207.6 L 459.865723 206.6 L 459.839689 205.6 L 459.812943 204.6 L 459.805197 203.6 L 459.800044 202.6 L 459.806242 201.6 L 459.812549 200.6 L 459.82013 199.6 L 459.847636 198.6 L 459.891869 197.6 L 459.921407 196.6 L 459.963254 195.6 L 460.022428 194.6 L 460.045138 193.6 L 460.08177 192.6 L 460.138558 191.6 L 460.163728 190.6 L 460.246424 189.6 L 460.333356 188.6 L 460.38404 187.6 L 460.421434 186.6 L 460.505814 185.6 L 460.540325 184.6 L 460.632316 183.6 L 460.719341 182.6 L 460.842481 181.6 L 460.88035 180.6 L 460.927825 179.6 L 461.033351 178.6 L 461.130812 177.6 L 461.207449 176.6 L 461.239376 175.6 L 461.293616 174.6 L 461.332467 173.6 L 461.406172 172.6 L 461.438168 171.6 L 461.494707 170.6 L 461.530823 169.6 L 461.599425 168.6 L 461.630841 167.6 L 461.685508 166.6 L 461.704279 165.6 L 461.749908 164.6 L 461.772811 163.6 L 461.781352 162.6 L 461.788693 161.6 L 461.794988 160.6 L 461.798165 159.6 L 461.799751 158.6 L 461.798288 157.6 L 461.785334 156.6 L 461.770712 155.6 L 461.758856 154.6 L 461.740831 153.6 L 461.720453 152.6 L 461.697054 151.6 L 461.682145 150.6 L 461.627431 149.6 L 461.593834 148.6 L 461.531138 147.6 L 461.503763 146.6 L 461.459783 145.6 L 461.380836 144.6 L 461.323308 143.6 L 461.273329 142.6 L 461.201345 141.6 L 461.164813 140.6 L 461.0965 139.6 L 461.008294 138.6 L 460.886947 137.6 L 460.821266 136.6 L 460.787648 135.6 L 460.723371 134.6 L 460.6774 133.6 L 460.605243 132.6 L 460.565417 131.6 L 460.522787 130.6 L 460.416828 129.6 L 460.364043 128.6 L 460.284766 127.6 L 460.242362 126.6 L 460.210096 125.6 L 460.17523 124.6 L 460.132572 123.6 L 460.100999 122.6 L 460.03342 121.6 L 459.996535 120.6 L 459.968579 119.6 L 459.947731 118.6 L 459.922118 117.6 L 459.8845 116.6 L 459.869658 115.6 L 459.844928 114.6 L 459.826698 113.6 L 459.815291 112.6 L 459.809656 111.6 L 459.804902 110.6 L 459.800293 109.6 L 459.801966 108.6 L 459.807748 107.6 L 459.827744 106.6 L 459.839396 105.6 L 459.850385 104.6 L 459.863352 103.6 L 459.913766 102.6 L 459.934588 101.6 L 459.962535 100.6 L 460.01928 99.6 L 460.041924 98.6 L 460.093327 97.6 L 460.134463 96.6 L 460.217232 95.6 L 460.265692 94.6 L 460.317119 93.6 L 460.368279 92.6 L 460.435578 91.6 L 460.468732 90.6 L 460.53479 89.6 L 460.590975 88.6 L 460.652254 87.6 L 460.692237 86.6 L 460.78866 85.6 L 460.90042 84.6 L 460.939339 83.6 L 461.037188 82.6 L 461.071842 81.6 L 461.155524 80.6 L 461.20603 79.6 L 461.275073 78.6 L 461.376176 77.6 L 461.428622 76.6 L 461.51793 75.6 L 461.582938 74.6 L 461.624483 73.6 L 461.666823 72.6 L 461.688843 71.6 L 461.72633 70.6 L 461.743582 69.6 L 461.76699 68.6 L 461.775557 67.6 L 461.784646 66.6 L 461.791714 65.6 L 461.798741 64.6 L 461.799849 63.6 L 461.799863 62.6 L 461.797189 61.6 L 461.794163 60.6 L 461.788696 59.6 L 461.768701 58.6 L 461.75673 57.6 L 461.729611 56.6 L 461.702599 55.6 L 461.675433 54.6 L 461.620958 53.6 L 461.591342 52.6 L 461.549586 51.6 L 461.476477 50.6 L 461.433039 49.6 L 461.362348 48.6 L 461.323941 47.6 L 461.263602 46.6 L 461.232847 45.6 L 461.202349 44.6 L 461.143439 43.6 L 461.100262 42.6 L 461.05865 41.6 L 461.009535 40.6 L 460.944448 39.6 L 460.878053 38.6 L 460.75329 37.6 L 460.709475 36.6 L 460.655147 35.6 L 460.548443 34.6 L 460.505943 33.6 L 460.468449 32.6 L 460.378953 31.6 L 460.32173 30.6 L 460.252087 29.6 L 460.203068 28.6 L 460.147123 27.6 L 460.099998 26.6 L 460.06111 25.6 L 460.007418 24.6 L 459.961847 23.6 L 459.92491 22.6 L 459.902834 21.6 L 459.869951 20.6 L 459.840231 19.6 L 459.827681 18.6 L 459.815782 17.6 L 459.810664 16.6 L 459.802775 15.6 L 459.800144 14.6 L 459.800942 13.6 L 459.804183 12.6 L 459.819321 11.6 L 459.826258 10.6 L 459.842635 9.6 L 459.861048 8.6 L 459.89064 7.6 L 459.912722 6.6 L 459.970416 5.6 L 459.995607 4.6 L 460.06392 3.6 L 460.111046 2.6 L 460.148394 1.6 L 460.203603 0 L 459.8 0.506966 L 458.8 0.403856 L 457.8 0.349882 L 456.8 0.319162 L 455.8 0.263621 L 454.8 0.225886 L 453.8 0.157632 L 452.8 0.121803 L 451.8 0.052019 L 450.8 -0.007275 L 449.8 -0.045882 L 448.8 -0.079878 L 447.8 -0.122458 L 446.8 -0.169107 L 445.8 -0.223673 L 444.8 -0.309574 L 443.8 -0.35625 L 442.8 -0.413565 L 441.8 -0.443979 L 440.8 -0.52903 L 439.8 -0.562705 L 438.8 -0.650629 L 437.8 -0.705614 L 436.8 -0.744303 L 435.8 -0.814334 L 434.8 -0.84478 L 433.8 -0.902505 L 432.8 -0.919649 L 431.8 -0.944384 L 430.8 -0.959884 L 429.8 -0.983336 L 428.8 -0.99015 L 427.8 -0.994083 L 426.8 -0.997815 L 425.8 -0.999848 L 424.8 -0.991462 L 423.8 -0.975076 L 422.8 -0.948806 L 421.8 -0.935477 L 420.8 -0.905523 L 419.8 -0.871272 L 418.8 -0.850602 L 417.8 -0.80959 L 416.8 -0.736272 L 415.8 -0.713054 L 414.8 -0.672688 L 413.8 -0.645437 L 412.8 -0.564899 L 411.8 -0.511421 L 410.8 -0.43285 L 409.8 -0.384382 L 408.8 -0.270352 L 407.8 -0.169667 L 406.8 -0.085243 L 405.8 0.006297 L 404.8 0.10871 L 403.8 0.149518 L 402.8 0.192661 L 401.8 0.231962 L 400.8 0.265385 L 399.8 0.308493 L 398.8 0.414072 L 397.8 0.469773 L 396.8 0.5751 L 395.8 0.672097 L 394.8 0.695117 L 393.8 0.722104 L 392.8 0.752205 L 391.8 0.825447 L 390.8 0.862839 L 389.8 0.897798 L 388.8 0.916374 L 387.8 0.94688 L 386.8 0.959092 L 385.8 0.968868 L 384.8 0.978437 L 383.8 0.986646 L 382.8 0.997922 L 381.8 0.999784 L 380.8 0.993482 L 379.8 0.987469 L 378.8 0.982012 L 377.8 0.96182 L 376.8 0.951931 L 375.8 0.924178 L 374.8 0.905171 L 373.8 0.889772 L 372.8 0.860507 L 371.8 0.796703 L 370.8 0.74765 L 369.8 0.677461 L 368.8 0.648352 L 367.8 0.588782 L 366.8 0.541833 L 365.8 0.490711 L 364.8 0.436658 L 363.8 0.354971 L 362.8 0.276314 L 361.8 0.239654 L 360.8 0.118 L 359.8 0.039058 L 358.8 -0.025433 L 357.8 -0.071061 L 356.8 -0.18671 L 355.8 -0.234985 L 354.8 -0.270508 L 353.8 -0.314086 L 352.8 -0.349862 L 351.8 -0.420687 L 350.8 -0.457091 L 349.8 -0.554567 L 348.8 -0.623631 L 347.8 -0.689597 L 346.8 -0.754127 L 345.8 -0.777549 L 344.8 -0.804954 L 343.8 -0.853448 L 342.8 -0.883441 L 341.8 -0.915979 L 340.8 -0.930722 L 339.8 -0.944262 L 338.8 -0.967697 L 337.8 -0.980177 L 336.8 -0.987315 L 335.8 -0.992913 L 334.8 -0.998519 L 333.8 -1 L 332.8 -0.994007 L 331.8 -0.988042 L 330.8 -0.97653 L 329.8 -0.952723 L 328.8 -0.94259 L 327.8 -0.900632 L 326.8 -0.85856 L 325.8 -0.827344 L 324.8 -0.757486 L 323.8 -0.71323 L 322.8 -0.63076 L 321.8 -0.542573 L 320.8 -0.497653 L 319.8 -0.401923 L 318.8 -0.329819 L 317.8 -0.234829 L 316.8 -0.178455 L 315.8 -0.134258 L 314.8 -0.078442 L 313.8 -0.038504 L 312.8 0.036947 L 311.8 0.094942 L 310.8 0.132129 L 309.8 0.190656 L 308.8 0.293433 L 307.8 0.35016 L 306.8 0.421165 L 305.8 0.482934 L 304.8 0.520397 L 303.8 0.555683 L 302.8 0.599101 L 301.8 0.64096 L 300.8 0.668583 L 299.8 0.719698 L 298.8 0.753234 L 297.8 0.815297 L 296.8 0.834939 L 295.8 0.896712 L 294.8 0.919191 L 293.8 0.939414 L 292.8 0.960103 L 291.8 0.98653 L 290.8 0.997487 L 289.8 0.999269 L 288.8 0.996641 L 287.8 0.990091 L 286.8 0.968128 L 285.8 0.929128 L 284.8 0.908845 L 283.8 0.892196 L 282.8 0.830573 L 281.8 0.801989 L 280.8 0.778481 L 279.8 0.734033 L 278.8 0.70807 L 277.8 0.65771 L 276.8 0.581318 L 275.8 0.553797 L 274.8 0.521939 L 273.8 0.486315 L 272.8 0.398542 L 271.8 0.301531 L 270.8 0.221578 L 269.8 0.103903 L 268.8 0.031909 L 267.8 -0.072257 L 266.8 -0.183566 L 265.8 -0.278988 L 264.8 -0.373885 L 263.8 -0.440904 L 262.8 -0.501789 L 261.8 -0.54625 L 260.8 -0.581921 L 259.8 -0.661217 L 258.8 -0.691472 L 257.8 -0.765116 L 256.8 -0.797561 L 255.8 -0.842088 L 254.8 -0.863344 L 253.8 -0.891696 L 252.8 -0.920022 L 251.8 -0.954355 L 250.8 -0.967671 L 249.8 -0.984463 L 248.8 -0.995007 L 247.8 -0.998126 L 246.8 -0.999962 L 245.8 -0.994973 L 244.8 -0.989525 L 243.8 -0.97538 L 242.8 -0.940746 L 241.8 -0.921719 L 240.8 -0.879119 L 239.8 -0.861014 L 238.8 -0.816611 L 237.8 -0.794181 L 236.8 -0.753913 L 235.8 -0.721408 L 234.8 -0.658097 L 233.8 -0.569587 L 232.8 -0.483117 L 231.8 -0.403482 L 230.8 -0.349696 L 229.8 -0.289585 L 228.8 -0.218544 L 227.8 -0.098423 L 226.8 0.006039 L 225.8 0.116842 L 224.8 0.170115 L 223.8 0.243365 L 222.8 0.281948 L 221.8 0.357711 L 220.8 0.435272 L 219.8 0.521412 L 218.8 0.548855 L 217.8 0.644831 L 216.8 0.720941 L 215.8 0.771105 L 214.8 0.825458 L 213.8 0.853129 L 212.8 0.889151 L 211.8 0.920712 L 210.8 0.938819 L 209.8 0.955558 L 208.8 0.972565 L 207.8 0.989619 L 206.8 0.99403 L 205.8 0.998289 L 204.8 0.999886 L 203.8 0.998359 L 202.8 0.995935 L 201.8 0.992476 L 200.8 0.982211 L 199.8 0.962483 L 198.8 0.950784 L 197.8 0.90804 L 196.8 0.88236 L 195.8 0.838178 L 194.8 0.782063 L 193.8 0.725365 L 192.8 0.693505 L 191.8 0.656796 L 190.8 0.628663 L 189.8 0.572864 L 188.8 0.538147 L 187.8 0.46646 L 186.8 0.410402 L 185.8 0.328747 L 184.8 0.273173 L 183.8 0.188865 L 182.8 0.14624 L 181.8 0.055234 L 180.8 -0.005051 L 179.8 -0.110128 L 178.8 -0.174313 L 177.8 -0.253509 L 176.8 -0.319736 L 175.8 -0.374012 L 174.8 -0.407139 L 173.8 -0.463853 L 172.8 -0.50741 L 171.8 -0.604653 L 170.8 -0.678599 L 169.8 -0.740393 L 168.8 -0.768808 L 167.8 -0.794142 L 166.8 -0.860397 L 165.8 -0.903414 L 164.8 -0.931921 L 163.8 -0.943915 L 162.8 -0.957989 L 161.8 -0.968817 L 160.8 -0.984115 L 159.8 -0.993971 L 158.8 -0.999784 L 157.8 -0.998949 L 156.8 -0.996987 L 155.8 -0.993379 L 154.8 -0.976068 L 153.8 -0.966337 L 152.8 -0.932307 L 151.8 -0.907236 L 150.8 -0.868539 L 149.8 -0.802605 L 148.8 -0.761617 L 147.8 -0.686776 L 146.8 -0.654849 L 145.8 -0.630635 L 144.8 -0.604815 L 143.8 -0.545775 L 142.8 -0.491063 L 141.8 -0.384861 L 140.8 -0.304585 L 139.8 -0.187843 L 138.8 -0.08788 L 137.8 -0.035566 L 136.8 0.003007 L 135.8 0.039368 L 134.8 0.160354 L 133.8 0.191539 L 132.8 0.227915 L 131.8 0.290066 L 130.8 0.378077 L 129.8 0.42247 L 128.8 0.470988 L 127.8 0.569778 L 126.8 0.611246 L 125.8 0.653898 L 124.8 0.718748 L 123.8 0.785183 L 122.8 0.805272 L 121.8 0.829751 L 120.8 0.870359 L 119.8 0.894905 L 118.8 0.911852 L 117.8 0.942871 L 116.8 0.965923 L 115.8 0.985366 L 114.8 0.992773 L 113.8 0.996995 L 112.8 0.999656 L 111.8 0.999239 L 110.8 0.993894 L 109.8 0.984738 L 108.8 0.972213 L 107.8 0.945446 L 106.8 0.91655 L 105.8 0.86624 L 104.8 0.837897 L 103.8 0.782994 L 102.8 0.745187 L 101.8 0.692498 L 100.8 0.662794 L 99.8 0.631793 L 98.8 0.601321 L 97.8 0.559084 L 96.8 0.531062 L 95.8 0.433515 L 94.8 0.35707 L 93.8 0.301773 L 92.8 0.220903 L 91.8 0.143522 L 90.8 0.062112 L 89.8 0.005147 L 88.8 -0.117966 L 87.8 -0.149535 L 86.8 -0.216766 L 85.8 -0.295058 L 84.8 -0.387611 L 83.8 -0.421765 L 82.8 -0.452679 L 81.8 -0.503004 L 80.8 -0.547822 L 79.8 -0.588823 L 78.8 -0.618678 L 77.8 -0.663526 L 76.8 -0.74679 L 75.8 -0.76885 L 74.8 -0.812967 L 73.8 -0.833129 L 72.8 -0.893251 L 71.8 -0.93548 L 70.8 -0.958737 L 69.8 -0.976732 L 68.8 -0.983734 L 67.8 -0.995973 L 66.8 -0.999442 L 65.8 -0.998259 L 64.8 -0.994084 L 63.8 -0.980354 L 62.8 -0.972703 L 61.8 -0.958263 L 60.8 -0.927611 L 59.8 -0.902922 L 58.8 -0.882675 L 57.8 -0.864202 L 56.8 -0.845248 L 55.8 -0.810642 L 54.8 -0.743359 L 53.8 -0.695131 L 52.8 -0.665749 L 51.8 -0.633906 L 50.8 -0.555682 L 49.8 -0.45647 L 48.8 -0.412576 L 47.8 -0.301816 L 46.8 -0.248043 L 45.8 -0.189835 L 44.8 -0.153658 L 43.8 -0.098867 L 42.8 -0.015916 L 41.8 0.031754 L 40.8 0.120599 L 39.8 0.168247 L 38.8 0.248469 L 37.8 0.337896 L 36.8 0.382122 L 35.8 0.441179 L 34.8 0.539628 L 33.8 0.57467 L 32.8 0.620434 L 31.8 0.673635 L 30.8 0.709483 L 29.8 0.751738 L 28.8 0.793097 L 27.8 0.820445 L 26.8 0.88147 L 25.8 0.904483 L 24.8 0.919261 L 23.8 0.934284 L 22.8 0.947208 L 21.8 0.979534 L 20.8 0.996802 L 19.8 0.999844 L 18.8 0.997823 L 17.8 0.99401 L 16.8 0.978994 L 15.8 0.970072 L 14.8 0.95778 L 13.8 0.929404 L 12.8 0.901094 L 11.8 0.866107 L 10.8 0.813717 L 9.8 0.765101 L 8.8 0.721134 L 7.8 0.682742 L 6.8 0.590438 L 5.8 0.563187 L 4.8 0.517238 L 3.8 0.475854 L 2.8 0.436431 L 1.8 0.377515 L 0 0.273593 L 0.227262 1 L 0.140289 2 L 0.091558 3 L 0.053928 4 L 0.017733 5 L -0.06793 6 L -0.161753 7 L -0.273189 8 L -0.360274 9 L -0.40709 10 L -0.463838 11 L -0.531601 12 L -0.573508 13 L -0.625352 14 L -0.650645 15 L -0.724163 16 L -0.770317 17 L -0.791479 18 L -0.851149 19 L -0.887991 20 L -0.917061 21 L -0.941292 22 L -0.951546 23 L -0.981839 24 L -0.994579 25 L -0.999784 26 L -0.999825 27 L -0.998417 28 L -0.992654 29 L -0.986301 30 L -0.967662 31 L -0.943214 32 L -0.912437 33 L -0.895086 34 L -0.880479 35 L -0.851999 36 L -0.833049 37 L -0.804776 38 L -0.736949 39 L -0.694852 40 L -0.659088 41 L -0.608192 42 L -0.546144 43 L -0.469078 44 L -0.390646 45 L -0.314256 46 L -0.272519 47 L -0.174586 48 L -0.104796 49 L -0.033939 50 L 0.084549 51 L 0.122597 52 L 0.158643 53 L 0.20132 54 L 0.299241 55 L 0.371531 56 L 0.414118 57 L 0.451421 58 L 0.546295 59 L 0.588994 60 L 0.621715 61 L 0.647784 62 L 0.677809 63 L 0.707013 64 L 0.742447 65 L 0.763133 66 L 0.785911 67 L 0.848282 68 L 0.876933 69 L 0.89743 70 L 0.932584 71 L 0.952705 72 L 0.963835 73 L 0.983785 74 L 0.997162 75 L 0.998974 76 L 0.993744 77 L 0.987133 78 L 0.961107 79 L 0.93948 80 L 0.917584 81 L 0.899066 82 L 0.868853 83 L 0.826455 84 L 0.799415 85 L 0.778893 86 L 0.743514 87 L 0.655618 88 L 0.618638 89 L 0.545793 90 L 0.443104 91 L 0.409892 92 L 0.309442 93 L 0.277702 94 L 0.234758 95 L 0.200953 96 L 0.120665 97 L 0.086322 98 L 0.0144 99 L -0.061467 100 L -0.117562 101 L -0.207304 102 L -0.24726 103 L -0.314957 104 L -0.42911 105 L -0.460269 106 L -0.525752 107 L -0.557786 108 L -0.642979 109 L -0.673037 110 L -0.719408 111 L -0.749116 112 L -0.778759 113 L -0.843855 114 L -0.877651 115 L -0.902804 116 L -0.918897 117 L -0.955058 118 L -0.973964 119 L -0.984187 120 L -0.992492 121 L -0.999215 122 L -0.996501 123 L -0.988797 124 L -0.971166 125 L -0.940938 126 L -0.912341 127 L -0.885031 128 L -0.825603 129 L -0.77009 130 L -0.688452 131 L -0.647196 132 L -0.60259 133 L -0.511042 134 L -0.430427 135 L -0.384469 136 L -0.292923 137 L -0.225967 138 L -0.179248 139 L -0.136118 140 L -0.077875 141 L -0.030604 142 L 0.026452 143 L 0.080989 144 L 0.196427 145 L 0.315576 146 L 0.370627 147 L 0.40698 148 L 0.502034 149 L 0.546466 150 L 0.575573 151 L 0.667237 152 L 0.714029 153 L 0.749742 154 L 0.795559 155 L 0.859505 156 L 0.892455 157 L 0.917515 158 L 0.933607 159 L 0.970088 160 L 0.979122 161 L 0.985274 162 L 0.990848 163 L 0.99806 164 L 0.99889 165 L 0.994277 166 L 0.981883 167 L 0.973583 168 L 0.937803 169 L 0.919049 170 L 0.901448 171 L 0.87707 172 L 0.844234 173 L 0.771924 174 L 0.735339 175 L 0.713128 176 L 0.683072 177 L 0.643552 178 L 0.614091 179 L 0.569454 180 L 0.500184 181 L 0.392301 182 L 0.355195 183 L 0.247165 184 L 0.140245 185 L 0.103559 186 L 0.051805 187 L -0.035129 188 L -0.106027 189 L -0.227181 190 L -0.260107 191 L -0.313632 192 L -0.359984 193 L -0.401339 194 L -0.450067 195 L -0.490327 196 L -0.533979 197 L -0.560575 198 L -0.651745 199 L -0.691652 200 L -0.720319 201 L -0.762616 202 L -0.811738 203 L -0.865675 204 L -0.918013 205 L -0.952001 206 L -0.967156 207 L -0.980387 208 L -0.992416 209 L -0.998222 210 L -0.99846 211 L -0.995029 212 L -0.978361 213 L -0.950969 214 L -0.910428 215 L -0.890133 216 L -0.872536 217 L -0.847806 218 L -0.794595 219 L -0.753623 220 L -0.693228 221 L -0.609661 222 L -0.563669 223 L -0.532753 224 L -0.502298 225 L -0.455614 226 L -0.387673 227 L -0.355756 228 L -0.30615 229 L -0.205734 230 L -0.170513 231 L -0.129026 232 L -0.0754 233 L -0.035334 234 L 0.07453 235 L 0.195709 236 L 0.233871 237 L 0.303602 238 L 0.362359 239 L 0.415477 240 L 0.479944 241 L 0.522985 242 L 0.587131 243 L 0.631929 244 L 0.71055 245 L 0.733761 246 L 0.756219 247 L 0.826066 248 L 0.846169 249 L 0.872053 250 L 0.895656 251 L 0.909427 252 L 0.933238 253 L 0.968289 254 L 0.987905 255 L 0.997925 256 L 0.999511 257 L 0.997397 258 L 0.994191 259 L 0.987806 260 L 0.972822 261 L 0.963505 262 L 0.943913 263 L 0.912031 264 L 0.858743 265 L 0.824485 266 L 0.803278 267 L 0.770858 268 L 0.745139 269 L 0.704247 270 L 0.679944 271 L 0.652386 272 L 0.613312 273 L 0.574818 274 L 0.521172 275 L 0.478431 276 L 0.446006 277 L 0.408082 278 L 0.378531 279 L 0.304491 280 L 0.26975 281 L 0.198648 282 L 0.140692 283 L 0.106477 284 L 0.001931 285 L -0.031948 286 L -0.139586 287 L -0.197401 288 L -0.263521 289 L -0.338446 290 L -0.397233 291 L -0.504686 292 L -0.600611 293 L -0.660743 294 L -0.694963 295 L -0.772666 296 L -0.810252 297 L -0.853431 298 L -0.881952 299 L -0.917155 300 L -0.941985 301 L -0.967909 302 L -0.983386 303 L -0.988682 304 L -0.999195 305 L -0.999894 306 L -0.998307 307 L -0.983759 308 L -0.976299 309 L -0.949036 310 L -0.904736 311 L -0.887316 312 L -0.847912 313 L -0.811558 314 L -0.773772 315 L -0.719976 316 L -0.6736 317 L -0.625248 318 L -0.57127 319 L -0.507815 320 L -0.41649 321 L -0.374633 322 L -0.343546 323 L -0.27172 324 L -0.238363 325 L -0.204546 326 L -0.16887 327 L -0.085534 328 L -0.053624 329 L 0.040791 330 L 0.163353 331 L 0.248217 332 L 0.307634 333 L 0.341295 334 L 0.436499 335 L 0.466063 336 L 0.500969 337 L 0.532344 338 L 0.629809 339 L 0.655764 340 L 0.706154 341 L 0.736458 342 L 0.792812 343 L 0.811609 344 L 0.857562 345.6 z " + style="fill: #ffffff" + id="path2" /> + </g> + <g + id="axes_1"> + <g + id="patch_2"> + <path + d="M 57.6 307.584 L 58.6 307.615436 L 59.6 307.652377 L 60.6 307.750123 L 61.6 307.782645 L 62.6 307.85627 L 63.6 307.894835 L 64.6 307.930248 L 65.6 307.987888 L 66.6 308.058274 L 67.6 308.110239 L 68.6 308.169328 L 69.6 308.257649 L 70.6 308.303794 L 71.6 308.346205 L 72.6 308.376697 L 73.6 308.402742 L 74.6 308.423942 L 75.6 308.478243 L 76.6 308.506181 L 77.6 308.535905 L 78.6 308.5613 L 79.6 308.5725 L 80.6 308.582624 L 81.6 308.58242 L 82.6 308.57291 L 83.6 308.561256 L 84.6 308.530227 L 85.6 308.519059 L 86.6 308.488942 L 87.6 308.429165 L 88.6 308.391973 L 89.6 308.352877 L 90.6 308.310437 L 91.6 308.277672 L 92.6 308.210246 L 93.6 308.17112 L 94.6 308.128445 L 95.6 308.057865 L 96.6 308.021474 L 97.6 307.963071 L 98.6 307.852118 L 99.6 307.78146 L 100.6 307.66852 L 101.6 307.622747 L 102.6 307.561464 L 103.6 307.512965 L 104.6 307.432142 L 105.6 307.313623 L 106.6 307.243412 L 107.6 307.16015 L 108.6 307.127008 L 109.6 307.075771 L 110.6 307.007372 L 111.6 306.941157 L 112.6 306.86424 L 113.6 306.836924 L 114.6 306.810447 L 115.6 306.787796 L 116.6 306.768265 L 117.6 306.741871 L 118.6 306.6921 L 119.6 306.657027 L 120.6 306.621161 L 121.6 306.605794 L 122.6 306.590025 L 123.6 306.586612 L 124.6 306.584195 L 125.6 306.584681 L 126.6 306.58661 L 127.6 306.599867 L 128.6 306.608258 L 129.6 306.629794 L 130.6 306.652827 L 131.6 306.67006 L 132.6 306.688523 L 133.6 306.708975 L 134.6 306.725575 L 135.6 306.788354 L 136.6 306.863619 L 137.6 306.896258 L 138.6 306.963822 L 139.6 307.017869 L 140.6 307.051573 L 141.6 307.141699 L 142.6 307.170234 L 143.6 307.20172 L 144.6 307.232731 L 145.6 307.287539 L 146.6 307.352126 L 147.6 307.390322 L 148.6 307.486256 L 149.6 307.535514 L 150.6 307.579583 L 151.6 307.619707 L 152.6 307.728074 L 153.6 307.769702 L 154.6 307.831844 L 155.6 307.901806 L 156.6 308.00631 L 157.6 308.043298 L 158.6 308.089175 L 159.6 308.15767 L 160.6 308.206416 L 161.6 308.284013 L 162.6 308.314554 L 163.6 308.384068 L 164.6 308.408041 L 165.6 308.436663 L 166.6 308.478456 L 167.6 308.500032 L 168.6 308.51398 L 169.6 308.540702 L 170.6 308.550012 L 171.6 308.562459 L 172.6 308.573514 L 173.6 308.579178 L 174.6 308.583942 L 175.6 308.578394 L 176.6 308.565106 L 177.6 308.557589 L 178.6 308.532804 L 179.6 308.509235 L 180.6 308.473055 L 181.6 308.447093 L 182.6 308.424771 L 183.6 308.356011 L 184.6 308.281476 L 185.6 308.187497 L 186.6 308.136445 L 187.6 308.082511 L 188.6 308.04726 L 189.6 307.941172 L 190.6 307.888908 L 191.6 307.852001 L 192.6 307.82097 L 193.6 307.759815 L 194.6 307.692395 L 195.6 307.643489 L 196.6 307.578297 L 197.6 307.540109 L 198.6 307.498113 L 199.6 307.456096 L 200.6 307.39658 L 201.6 307.28342 L 202.6 307.231169 L 203.6 307.191751 L 204.6 307.14465 L 205.6 307.08787 L 206.6 307.055207 L 207.6 307.019029 L 208.6 306.986939 L 209.6 306.952659 L 210.6 306.894281 L 211.6 306.849096 L 212.6 306.819472 L 213.6 306.769086 L 214.6 306.743889 L 215.6 306.722838 L 216.6 306.68787 L 217.6 306.66358 L 218.6 306.649513 L 219.6 306.630571 L 220.6 306.61491 L 221.6 306.602358 L 222.6 306.596522 L 223.6 306.58964 L 224.6 306.584466 L 225.6 306.586249 L 226.6 306.588974 L 227.6 306.600128 L 228.6 306.628363 L 229.6 306.672151 L 230.6 306.69284 L 231.6 306.733813 L 232.6 306.773888 L 233.6 306.792998 L 234.6 306.815507 L 235.6 306.882158 L 236.6 306.931868 L 237.6 307.005574 L 238.6 307.036888 L 239.6 307.11351 L 240.6 307.151808 L 241.6 307.225925 L 242.6 307.329983 L 243.6 307.399814 L 244.6 307.505048 L 245.6 307.560063 L 246.6 307.683538 L 247.6 307.754097 L 248.6 307.869936 L 249.6 307.920117 L 250.6 307.955721 L 251.6 308.047128 L 252.6 308.100636 L 253.6 308.188544 L 254.6 308.257729 L 255.6 308.304493 L 256.6 308.376537 L 257.6 308.426679 L 258.6 308.444069 L 259.6 308.471072 L 260.6 308.490499 L 261.6 308.509837 L 262.6 308.548086 L 263.6 308.564519 L 264.6 308.572888 L 265.6 308.577207 L 266.6 308.583762 L 267.6 308.581216 L 268.6 308.575757 L 269.6 308.559329 L 270.6 308.527394 L 271.6 308.489414 L 272.6 308.45461 L 273.6 308.391538 L 274.6 308.370111 L 275.6 308.319493 L 276.6 308.294536 L 277.6 308.238902 L 278.6 308.207673 L 279.6 308.157529 L 280.6 308.125036 L 281.6 308.044624 L 282.6 307.975698 L 283.6 307.860001 L 284.6 307.784522 L 285.6 307.668997 L 286.6 307.589513 L 287.6 307.481072 L 288.6 307.441704 L 289.6 307.338836 L 290.6 307.239038 L 291.6 307.193541 L 292.6 307.159219 L 293.6 307.107263 L 294.6 307.067616 L 295.6 307.032102 L 296.6 306.964457 L 297.6 306.925375 L 298.6 306.874894 L 299.6 306.825588 L 300.6 306.774518 L 301.6 306.730279 L 302.6 306.708259 L 303.6 306.692703 L 304.6 306.650256 L 305.6 306.635388 L 306.6 306.61266 L 307.6 306.592344 L 308.6 306.586547 L 309.6 306.584065 L 310.6 306.587122 L 311.6 306.598718 L 312.6 306.615638 L 313.6 306.647299 L 314.6 306.661382 L 315.6 306.714054 L 316.6 306.763143 L 317.6 306.817844 L 318.6 306.862192 L 319.6 306.932184 L 320.6 306.982567 L 321.6 307.036474 L 322.6 307.105913 L 323.6 307.163301 L 324.6 307.213466 L 325.6 307.290628 L 326.6 307.348818 L 327.6 307.409456 L 328.6 307.446657 L 329.6 307.511749 L 330.6 307.616879 L 331.6 307.677181 L 332.6 307.773503 L 333.6 307.805506 L 334.6 307.856523 L 335.6 307.973315 L 336.6 308.008762 L 337.6 308.064642 L 338.6 308.095018 L 339.6 308.183404 L 340.6 308.228168 L 341.6 308.309056 L 342.6 308.369202 L 343.6 308.432288 L 344.6 308.455236 L 345.6 308.471406 L 346.6 308.500335 L 347.6 308.530687 L 348.6 308.543261 L 349.6 308.56814 L 350.6 308.580224 L 351.6 308.583986 L 352.6 308.57955 L 353.6 308.567211 L 354.6 308.552798 L 355.6 308.536725 L 356.6 308.501204 L 357.6 308.48127 L 358.6 308.424681 L 359.6 308.357487 L 360.6 308.330117 L 361.6 308.295969 L 362.6 308.247289 L 363.6 308.199004 L 364.6 308.139927 L 365.6 308.044322 L 366.6 308.001182 L 367.6 307.951334 L 368.6 307.8928 L 369.6 307.845214 L 370.6 307.784086 L 371.6 307.728001 L 372.6 307.65383 L 373.6 307.536592 L 374.6 307.480868 L 375.6 307.372642 L 376.6 307.266492 L 377.6 307.15892 L 378.6 307.124412 L 379.6 307.021105 L 380.6 306.945381 L 381.6 306.905946 L 382.6 306.866562 L 383.6 306.84408 L 384.6 306.788267 L 385.6 306.762215 L 386.6 306.73198 L 387.6 306.681209 L 388.6 306.662558 L 389.6 306.640849 L 390.6 306.628203 L 391.6 306.60921 L 392.6 306.59182 L 393.6 306.584782 L 394.6 306.585806 L 395.6 306.59281 L 396.6 306.60218 L 397.6 306.625578 L 398.6 306.650661 L 399.6 306.66306 L 400.6 306.696153 L 401.6 306.71252 L 402.6 306.730925 L 403.6 306.780062 L 404.6 306.823875 L 405.6 306.86696 L 406.6 306.889901 L 407.6 306.930164 L 408.6 307.015024 L 409.6 307.057416 L 410.6 307.121802 L 411.6 307.166091 L 412.6 307.273937 L 413.6 307.350877 L 414.72 307.387319 L 414.578206 306.584 L 414.653307 305.584 L 414.711902 304.584 L 414.748477 303.584 L 414.860524 302.584 L 414.922209 301.584 L 414.972729 300.584 L 415.071514 299.584 L 415.109536 298.584 L 415.144984 297.584 L 415.236618 296.584 L 415.27989 295.584 L 415.333219 294.584 L 415.366084 293.584 L 415.428978 292.584 L 415.482832 291.584 L 415.539958 290.584 L 415.562048 289.584 L 415.605787 288.584 L 415.652881 287.584 L 415.669728 286.584 L 415.697802 285.584 L 415.708798 284.584 L 415.713367 283.584 L 415.719015 282.584 L 415.719066 281.584 L 415.715976 280.584 L 415.712463 279.584 L 415.706641 278.584 L 415.693789 277.584 L 415.670164 276.584 L 415.65528 275.584 L 415.631708 274.584 L 415.595389 273.584 L 415.563806 272.584 L 415.533913 271.584 L 415.455221 270.584 L 415.41867 269.584 L 415.392947 268.584 L 415.322274 267.584 L 415.231172 266.584 L 415.169215 265.584 L 415.135602 264.584 L 415.101102 263.584 L 415.003662 262.584 L 414.956072 261.584 L 414.924566 260.584 L 414.880881 259.584 L 414.810712 258.584 L 414.760845 257.584 L 414.726168 256.584 L 414.61652 255.584 L 414.583049 254.584 L 414.545707 253.584 L 414.465462 252.584 L 414.426968 251.584 L 414.385191 250.584 L 414.342766 249.584 L 414.233038 248.584 L 414.144753 247.584 L 414.070107 246.584 L 413.98165 245.584 L 413.907588 244.584 L 413.858423 243.584 L 413.802806 242.584 L 413.768106 241.584 L 413.756235 240.584 L 413.734012 239.584 L 413.722033 238.584 L 413.720281 237.584 L 413.725698 236.584 L 413.741896 235.584 L 413.758396 234.584 L 413.789579 233.584 L 413.802944 232.584 L 413.832587 231.584 L 413.89561 230.584 L 413.944931 229.584 L 413.99102 228.584 L 414.073247 227.584 L 414.11915 226.584 L 414.153475 225.584 L 414.207014 224.584 L 414.295901 223.584 L 414.327039 222.584 L 414.435088 221.584 L 414.54716 220.584 L 414.582598 219.584 L 414.667384 218.584 L 414.732991 217.584 L 414.835045 216.584 L 414.95126 215.584 L 414.991951 214.584 L 415.03304 213.584 L 415.069681 212.584 L 415.110677 211.584 L 415.186746 210.584 L 415.262812 209.584 L 415.2935 208.584 L 415.319991 207.584 L 415.376572 206.584 L 415.421088 205.584 L 415.451106 204.584 L 415.478162 203.584 L 415.520727 202.584 L 415.573592 201.584 L 415.604513 200.584 L 415.630788 199.584 L 415.645721 198.584 L 415.67601 197.584 L 415.697339 196.584 L 415.714228 195.584 L 415.718943 194.584 L 415.719553 193.584 L 415.717507 192.584 L 415.711646 191.584 L 415.692999 190.584 L 415.660942 189.584 L 415.614502 188.584 L 415.572556 187.584 L 415.505851 186.584 L 415.436785 185.584 L 415.38941 184.584 L 415.337891 183.584 L 415.298191 182.584 L 415.228771 181.584 L 415.16224 180.584 L 415.053331 179.584 L 414.988083 178.584 L 414.879875 177.584 L 414.818871 176.584 L 414.770186 175.584 L 414.693952 174.584 L 414.634421 173.584 L 414.559793 172.584 L 414.440966 171.584 L 414.343021 170.584 L 414.263973 169.584 L 414.218226 168.584 L 414.190954 167.584 L 414.147292 166.584 L 414.098708 165.584 L 414.066974 164.584 L 413.986744 163.584 L 413.920251 162.584 L 413.896226 161.584 L 413.835727 160.584 L 413.813495 159.584 L 413.794895 158.584 L 413.765569 157.584 L 413.749868 156.584 L 413.741569 155.584 L 413.731333 154.584 L 413.72099 153.584 L 413.721668 152.584 L 413.725448 151.584 L 413.741889 150.584 L 413.754023 149.584 L 413.764618 148.584 L 413.795995 147.584 L 413.821768 146.584 L 413.853177 145.584 L 413.875986 144.584 L 413.89358 143.584 L 413.943392 142.584 L 413.991052 141.584 L 414.062761 140.584 L 414.118524 139.584 L 414.144722 138.584 L 414.17549 137.584 L 414.265248 136.584 L 414.350042 135.584 L 414.415636 134.584 L 414.461461 133.584 L 414.504458 132.584 L 414.565971 131.584 L 414.665796 130.584 L 414.710226 129.584 L 414.760276 128.584 L 414.882117 127.584 L 414.94181 126.584 L 414.973376 125.584 L 415.005719 124.584 L 415.060279 123.584 L 415.102779 122.584 L 415.154251 121.584 L 415.242636 120.584 L 415.276833 119.584 L 415.320767 118.584 L 415.38448 117.584 L 415.459677 116.584 L 415.488491 115.584 L 415.530695 114.584 L 415.57328 113.584 L 415.590172 112.584 L 415.612653 111.584 L 415.65499 110.584 L 415.68495 109.584 L 415.703583 108.584 L 415.713375 107.584 L 415.717138 106.584 L 415.719976 105.584 L 415.718227 104.584 L 415.708871 103.584 L 415.698174 102.584 L 415.688304 101.584 L 415.669446 100.584 L 415.639107 99.584 L 415.600716 98.584 L 415.54123 97.584 L 415.497941 96.584 L 415.437203 95.584 L 415.353129 94.584 L 415.304836 93.584 L 415.261259 92.584 L 415.234378 91.584 L 415.202448 90.584 L 415.135256 89.584 L 415.054435 88.584 L 414.97889 87.584 L 414.93516 86.584 L 414.855265 85.584 L 414.793786 84.584 L 414.730161 83.584 L 414.622912 82.584 L 414.504202 81.584 L 414.462296 80.584 L 414.419342 79.584 L 414.357143 78.584 L 414.327006 77.584 L 414.294488 76.584 L 414.242553 75.584 L 414.137003 74.584 L 414.088557 73.584 L 414.042233 72.584 L 414.008417 71.584 L 413.96054 70.584 L 413.905662 69.584 L 413.881751 68.584 L 413.855714 67.584 L 413.799597 66.584 L 413.785723 65.584 L 413.759689 64.584 L 413.732943 63.584 L 413.725197 62.584 L 413.720044 61.584 L 413.726242 60.584 L 413.732549 59.584 L 413.74013 58.584 L 413.767636 57.584 L 413.811869 56.584 L 413.841407 55.584 L 413.883254 54.584 L 413.942428 53.584 L 413.965138 52.584 L 414.00177 51.584 L 414.058558 50.584 L 414.083728 49.584 L 414.166424 48.584 L 414.253356 47.584 L 414.30404 46.584 L 414.341434 45.584 L 414.425814 44.584 L 414.460325 43.584 L 414.552316 42.584 L 414.639341 41.472 L 413.72 41.429519 L 412.72 41.39165 L 411.72 41.344175 L 410.72 41.238649 L 409.72 41.141188 L 408.72 41.064551 L 407.72 41.032624 L 406.72 40.978384 L 405.72 40.939533 L 404.72 40.865828 L 403.72 40.833832 L 402.72 40.777293 L 401.72 40.741177 L 400.72 40.672575 L 399.72 40.641159 L 398.72 40.586492 L 397.72 40.567721 L 396.72 40.522092 L 395.72 40.499189 L 394.72 40.490648 L 393.72 40.483307 L 392.72 40.477012 L 391.72 40.473835 L 390.72 40.472249 L 389.72 40.473712 L 388.72 40.486666 L 387.72 40.501288 L 386.72 40.513144 L 385.72 40.531169 L 384.72 40.551547 L 383.72 40.574946 L 382.72 40.589855 L 381.72 40.644569 L 380.72 40.678166 L 379.72 40.740862 L 378.72 40.768237 L 377.72 40.812217 L 376.72 40.891164 L 375.72 40.948692 L 374.72 40.998671 L 373.72 41.070655 L 372.72 41.107187 L 371.72 41.1755 L 370.72 41.263706 L 369.72 41.385053 L 368.72 41.450734 L 367.72 41.484352 L 366.72 41.548629 L 365.72 41.5946 L 364.72 41.666757 L 363.72 41.706583 L 362.72 41.749213 L 361.72 41.855172 L 360.72 41.907957 L 359.72 41.987234 L 358.72 42.029638 L 357.72 42.061904 L 356.72 42.09677 L 355.72 42.139428 L 354.72 42.171001 L 353.72 42.23858 L 352.72 42.275465 L 351.72 42.303421 L 350.72 42.324269 L 349.72 42.349882 L 348.72 42.3875 L 347.72 42.402342 L 346.72 42.427072 L 345.72 42.445302 L 344.72 42.456709 L 343.72 42.462344 L 342.72 42.467098 L 341.72 42.471707 L 340.72 42.470034 L 339.72 42.464252 L 338.72 42.444256 L 337.72 42.432604 L 336.72 42.421615 L 335.72 42.408648 L 334.72 42.358234 L 333.72 42.337412 L 332.72 42.309465 L 331.72 42.25272 L 330.72 42.230076 L 329.72 42.178673 L 328.72 42.137537 L 327.72 42.054768 L 326.72 42.006308 L 325.72 41.954881 L 324.72 41.903721 L 323.72 41.836422 L 322.72 41.803268 L 321.72 41.73721 L 320.72 41.681025 L 319.72 41.619746 L 318.72 41.579763 L 317.72 41.48334 L 316.72 41.37158 L 315.72 41.332661 L 314.72 41.234812 L 313.72 41.200158 L 312.72 41.116476 L 311.72 41.06597 L 310.72 40.996927 L 309.72 40.895824 L 308.72 40.843378 L 307.72 40.75407 L 306.72 40.689062 L 305.72 40.647517 L 304.72 40.605177 L 303.72 40.583157 L 302.72 40.54567 L 301.72 40.528418 L 300.72 40.50501 L 299.72 40.496443 L 298.72 40.487354 L 297.72 40.480286 L 296.72 40.473259 L 295.72 40.472151 L 294.72 40.472137 L 293.72 40.474811 L 292.72 40.477837 L 291.72 40.483304 L 290.72 40.503299 L 289.72 40.51527 L 288.72 40.542389 L 287.72 40.569401 L 286.72 40.596567 L 285.72 40.651042 L 284.72 40.680658 L 283.72 40.722414 L 282.72 40.795523 L 281.72 40.838961 L 280.72 40.909652 L 279.72 40.948059 L 278.72 41.008398 L 277.72 41.039153 L 276.72 41.069651 L 275.72 41.128561 L 274.72 41.171738 L 273.72 41.21335 L 272.72 41.262465 L 271.72 41.327552 L 270.72 41.393947 L 269.72 41.51871 L 268.72 41.562525 L 267.72 41.616853 L 266.72 41.723557 L 265.72 41.766057 L 264.72 41.803551 L 263.72 41.893047 L 262.72 41.95027 L 261.72 42.019913 L 260.72 42.068932 L 259.72 42.124877 L 258.72 42.172002 L 257.72 42.21089 L 256.72 42.264582 L 255.72 42.310153 L 254.72 42.34709 L 253.72 42.369166 L 252.72 42.402049 L 251.72 42.431769 L 250.72 42.444319 L 249.72 42.456218 L 248.72 42.461336 L 247.72 42.469225 L 246.72 42.471856 L 245.72 42.471058 L 244.72 42.467817 L 243.72 42.452679 L 242.72 42.445742 L 241.72 42.429365 L 240.72 42.410952 L 239.72 42.38136 L 238.72 42.359278 L 237.72 42.301584 L 236.72 42.276393 L 235.72 42.20808 L 234.72 42.160954 L 233.72 42.123606 L 232.72 42.068397 L 231.72 41.978966 L 230.72 41.875856 L 229.72 41.821882 L 228.72 41.791162 L 227.72 41.735621 L 226.72 41.697886 L 225.72 41.629632 L 224.72 41.593803 L 223.72 41.524019 L 222.72 41.464725 L 221.72 41.426118 L 220.72 41.392122 L 219.72 41.349542 L 218.72 41.302893 L 217.72 41.248327 L 216.72 41.162426 L 215.72 41.11575 L 214.72 41.058435 L 213.72 41.028021 L 212.72 40.94297 L 211.72 40.909295 L 210.72 40.821371 L 209.72 40.766386 L 208.72 40.727697 L 207.72 40.657666 L 206.72 40.62722 L 205.72 40.569495 L 204.72 40.552351 L 203.72 40.527616 L 202.72 40.512116 L 201.72 40.488664 L 200.72 40.48185 L 199.72 40.477917 L 198.72 40.474185 L 197.72 40.472152 L 196.72 40.480538 L 195.72 40.496924 L 194.72 40.523194 L 193.72 40.536523 L 192.72 40.566477 L 191.72 40.600728 L 190.72 40.621398 L 189.72 40.66241 L 188.72 40.735728 L 187.72 40.758946 L 186.72 40.799312 L 185.72 40.826563 L 184.72 40.907101 L 183.72 40.960579 L 182.72 41.03915 L 181.72 41.087618 L 180.72 41.201648 L 179.72 41.302333 L 178.72 41.386757 L 177.72 41.478297 L 176.72 41.58071 L 175.72 41.621518 L 174.72 41.664661 L 173.72 41.703962 L 172.72 41.737385 L 171.72 41.780493 L 170.72 41.886072 L 169.72 41.941773 L 168.72 42.0471 L 167.72 42.144097 L 166.72 42.167117 L 165.72 42.194104 L 164.72 42.224205 L 163.72 42.297447 L 162.72 42.334839 L 161.72 42.369798 L 160.72 42.388374 L 159.72 42.41888 L 158.72 42.431092 L 157.72 42.440868 L 156.72 42.450437 L 155.72 42.458646 L 154.72 42.469922 L 153.72 42.471784 L 152.72 42.465482 L 151.72 42.459469 L 150.72 42.454012 L 149.72 42.43382 L 148.72 42.423931 L 147.72 42.396178 L 146.72 42.377171 L 145.72 42.361772 L 144.72 42.332507 L 143.72 42.268703 L 142.72 42.21965 L 141.72 42.149461 L 140.72 42.120352 L 139.72 42.060782 L 138.72 42.013833 L 137.72 41.962711 L 136.72 41.908658 L 135.72 41.826971 L 134.72 41.748314 L 133.72 41.711654 L 132.72 41.59 L 131.72 41.511058 L 130.72 41.446567 L 129.72 41.400939 L 128.72 41.28529 L 127.72 41.237015 L 126.72 41.201492 L 125.72 41.157914 L 124.72 41.122138 L 123.72 41.051313 L 122.72 41.014909 L 121.72 40.917433 L 120.72 40.848369 L 119.72 40.782403 L 118.72 40.717873 L 117.72 40.694451 L 116.72 40.667046 L 115.72 40.618552 L 114.72 40.588559 L 113.72 40.556021 L 112.72 40.541278 L 111.72 40.527738 L 110.72 40.504303 L 109.72 40.491823 L 108.72 40.484685 L 107.72 40.479087 L 106.72 40.473481 L 105.72 40.472 L 104.72 40.477993 L 103.72 40.483958 L 102.72 40.49547 L 101.72 40.519277 L 100.72 40.52941 L 99.72 40.571368 L 98.72 40.61344 L 97.72 40.644656 L 96.72 40.714514 L 95.72 40.75877 L 94.72 40.84124 L 93.72 40.929427 L 92.72 40.974347 L 91.72 41.070077 L 90.72 41.142181 L 89.72 41.237171 L 88.72 41.293545 L 87.72 41.337742 L 86.72 41.393558 L 85.72 41.433496 L 84.72 41.508947 L 83.72 41.566942 L 82.72 41.604129 L 81.72 41.662656 L 80.72 41.765433 L 79.72 41.82216 L 78.72 41.893165 L 77.72 41.954934 L 76.72 41.992397 L 75.72 42.027683 L 74.72 42.071101 L 73.72 42.11296 L 72.72 42.140583 L 71.72 42.191698 L 70.72 42.225234 L 69.72 42.287297 L 68.72 42.306939 L 67.72 42.368712 L 66.72 42.391191 L 65.72 42.411414 L 64.72 42.432103 L 63.72 42.45853 L 62.72 42.469487 L 61.72 42.471269 L 60.72 42.468641 L 59.72 42.462091 L 58.72 42.440128 L 57.6 42.401128 L 58.508845 42.472 L 58.492196 43.472 L 58.430573 44.472 L 58.401989 45.472 L 58.378481 46.472 L 58.334033 47.472 L 58.30807 48.472 L 58.25771 49.472 L 58.181318 50.472 L 58.153797 51.472 L 58.121939 52.472 L 58.086315 53.472 L 57.998542 54.472 L 57.901531 55.472 L 57.821578 56.472 L 57.703903 57.472 L 57.631909 58.472 L 57.527743 59.472 L 57.416434 60.472 L 57.321012 61.472 L 57.226115 62.472 L 57.159096 63.472 L 57.098211 64.472 L 57.05375 65.472 L 57.018079 66.472 L 56.938783 67.472 L 56.908528 68.472 L 56.834884 69.472 L 56.802439 70.472 L 56.757912 71.472 L 56.736656 72.472 L 56.708304 73.472 L 56.679978 74.472 L 56.645645 75.472 L 56.632329 76.472 L 56.615537 77.472 L 56.604993 78.472 L 56.601874 79.472 L 56.600038 80.472 L 56.605027 81.472 L 56.610475 82.472 L 56.62462 83.472 L 56.659254 84.472 L 56.678281 85.472 L 56.720881 86.472 L 56.738986 87.472 L 56.783389 88.472 L 56.805819 89.472 L 56.846087 90.472 L 56.878592 91.472 L 56.941903 92.472 L 57.030413 93.472 L 57.116883 94.472 L 57.196518 95.472 L 57.250304 96.472 L 57.310415 97.472 L 57.381456 98.472 L 57.501577 99.472 L 57.606039 100.472 L 57.716842 101.472 L 57.770115 102.472 L 57.843365 103.472 L 57.881948 104.472 L 57.957711 105.472 L 58.035272 106.472 L 58.121412 107.472 L 58.148855 108.472 L 58.244831 109.472 L 58.320941 110.472 L 58.371105 111.472 L 58.425458 112.472 L 58.453129 113.472 L 58.489151 114.472 L 58.520712 115.472 L 58.538819 116.472 L 58.555558 117.472 L 58.572565 118.472 L 58.589619 119.472 L 58.59403 120.472 L 58.598289 121.472 L 58.599886 122.472 L 58.598359 123.472 L 58.595935 124.472 L 58.592476 125.472 L 58.582211 126.472 L 58.562483 127.472 L 58.550784 128.472 L 58.50804 129.472 L 58.48236 130.472 L 58.438178 131.472 L 58.382063 132.472 L 58.325365 133.472 L 58.293505 134.472 L 58.256796 135.472 L 58.228663 136.472 L 58.172864 137.472 L 58.138147 138.472 L 58.06646 139.472 L 58.010402 140.472 L 57.928747 141.472 L 57.873173 142.472 L 57.788865 143.472 L 57.74624 144.472 L 57.655234 145.472 L 57.594949 146.472 L 57.489872 147.472 L 57.425687 148.472 L 57.346491 149.472 L 57.280264 150.472 L 57.225988 151.472 L 57.192861 152.472 L 57.136147 153.472 L 57.09259 154.472 L 56.995347 155.472 L 56.921401 156.472 L 56.859607 157.472 L 56.831192 158.472 L 56.805858 159.472 L 56.739603 160.472 L 56.696586 161.472 L 56.668079 162.472 L 56.656085 163.472 L 56.642011 164.472 L 56.631183 165.472 L 56.615885 166.472 L 56.606029 167.472 L 56.600216 168.472 L 56.601051 169.472 L 56.603013 170.472 L 56.606621 171.472 L 56.623932 172.472 L 56.633663 173.472 L 56.667693 174.472 L 56.692764 175.472 L 56.731461 176.472 L 56.797395 177.472 L 56.838383 178.472 L 56.913224 179.472 L 56.945151 180.472 L 56.969365 181.472 L 56.995185 182.472 L 57.054225 183.472 L 57.108937 184.472 L 57.215139 185.472 L 57.295415 186.472 L 57.412157 187.472 L 57.51212 188.472 L 57.564434 189.472 L 57.603007 190.472 L 57.639368 191.472 L 57.760354 192.472 L 57.791539 193.472 L 57.827915 194.472 L 57.890066 195.472 L 57.978077 196.472 L 58.02247 197.472 L 58.070988 198.472 L 58.169778 199.472 L 58.211246 200.472 L 58.253898 201.472 L 58.318748 202.472 L 58.385183 203.472 L 58.405272 204.472 L 58.429751 205.472 L 58.470359 206.472 L 58.494905 207.472 L 58.511852 208.472 L 58.542871 209.472 L 58.565923 210.472 L 58.585366 211.472 L 58.592773 212.472 L 58.596995 213.472 L 58.599656 214.472 L 58.599239 215.472 L 58.593894 216.472 L 58.584738 217.472 L 58.572213 218.472 L 58.545446 219.472 L 58.51655 220.472 L 58.46624 221.472 L 58.437897 222.472 L 58.382994 223.472 L 58.345187 224.472 L 58.292498 225.472 L 58.262794 226.472 L 58.231793 227.472 L 58.201321 228.472 L 58.159084 229.472 L 58.131062 230.472 L 58.033515 231.472 L 57.95707 232.472 L 57.901773 233.472 L 57.820903 234.472 L 57.743522 235.472 L 57.662112 236.472 L 57.605147 237.472 L 57.482034 238.472 L 57.450465 239.472 L 57.383234 240.472 L 57.304942 241.472 L 57.212389 242.472 L 57.178235 243.472 L 57.147321 244.472 L 57.096996 245.472 L 57.052178 246.472 L 57.011177 247.472 L 56.981322 248.472 L 56.936474 249.472 L 56.85321 250.472 L 56.83115 251.472 L 56.787033 252.472 L 56.766871 253.472 L 56.706749 254.472 L 56.66452 255.472 L 56.641263 256.472 L 56.623268 257.472 L 56.616266 258.472 L 56.604027 259.472 L 56.600558 260.472 L 56.601741 261.472 L 56.605916 262.472 L 56.619646 263.472 L 56.627297 264.472 L 56.641737 265.472 L 56.672389 266.472 L 56.697078 267.472 L 56.717325 268.472 L 56.735798 269.472 L 56.754752 270.472 L 56.789358 271.472 L 56.856641 272.472 L 56.904869 273.472 L 56.934251 274.472 L 56.966094 275.472 L 57.044318 276.472 L 57.14353 277.472 L 57.187424 278.472 L 57.298184 279.472 L 57.351957 280.472 L 57.410165 281.472 L 57.446342 282.472 L 57.501133 283.472 L 57.584084 284.472 L 57.631754 285.472 L 57.720599 286.472 L 57.768247 287.472 L 57.848469 288.472 L 57.937896 289.472 L 57.982122 290.472 L 58.041179 291.472 L 58.139628 292.472 L 58.17467 293.472 L 58.220434 294.472 L 58.273635 295.472 L 58.309483 296.472 L 58.351738 297.472 L 58.393097 298.472 L 58.420445 299.472 L 58.48147 300.472 L 58.504483 301.472 L 58.519261 302.472 L 58.534284 303.472 L 58.547208 304.472 L 58.579534 305.472 L 58.596802 306.472 L 58.599844 307.584 z " + style="fill: #ffffff; stroke: #ffffff; stroke-width: 4; stroke-linejoin: miter" + id="path3" /> + <path + d="M 57.6 307.584 L 58.6 307.615436 L 59.6 307.652377 L 60.6 307.750123 L 61.6 307.782645 L 62.6 307.85627 L 63.6 307.894835 L 64.6 307.930248 L 65.6 307.987888 L 66.6 308.058274 L 67.6 308.110239 L 68.6 308.169328 L 69.6 308.257649 L 70.6 308.303794 L 71.6 308.346205 L 72.6 308.376697 L 73.6 308.402742 L 74.6 308.423942 L 75.6 308.478243 L 76.6 308.506181 L 77.6 308.535905 L 78.6 308.5613 L 79.6 308.5725 L 80.6 308.582624 L 81.6 308.58242 L 82.6 308.57291 L 83.6 308.561256 L 84.6 308.530227 L 85.6 308.519059 L 86.6 308.488942 L 87.6 308.429165 L 88.6 308.391973 L 89.6 308.352877 L 90.6 308.310437 L 91.6 308.277672 L 92.6 308.210246 L 93.6 308.17112 L 94.6 308.128445 L 95.6 308.057865 L 96.6 308.021474 L 97.6 307.963071 L 98.6 307.852118 L 99.6 307.78146 L 100.6 307.66852 L 101.6 307.622747 L 102.6 307.561464 L 103.6 307.512965 L 104.6 307.432142 L 105.6 307.313623 L 106.6 307.243412 L 107.6 307.16015 L 108.6 307.127008 L 109.6 307.075771 L 110.6 307.007372 L 111.6 306.941157 L 112.6 306.86424 L 113.6 306.836924 L 114.6 306.810447 L 115.6 306.787796 L 116.6 306.768265 L 117.6 306.741871 L 118.6 306.6921 L 119.6 306.657027 L 120.6 306.621161 L 121.6 306.605794 L 122.6 306.590025 L 123.6 306.586612 L 124.6 306.584195 L 125.6 306.584681 L 126.6 306.58661 L 127.6 306.599867 L 128.6 306.608258 L 129.6 306.629794 L 130.6 306.652827 L 131.6 306.67006 L 132.6 306.688523 L 133.6 306.708975 L 134.6 306.725575 L 135.6 306.788354 L 136.6 306.863619 L 137.6 306.896258 L 138.6 306.963822 L 139.6 307.017869 L 140.6 307.051573 L 141.6 307.141699 L 142.6 307.170234 L 143.6 307.20172 L 144.6 307.232731 L 145.6 307.287539 L 146.6 307.352126 L 147.6 307.390322 L 148.6 307.486256 L 149.6 307.535514 L 150.6 307.579583 L 151.6 307.619707 L 152.6 307.728074 L 153.6 307.769702 L 154.6 307.831844 L 155.6 307.901806 L 156.6 308.00631 L 157.6 308.043298 L 158.6 308.089175 L 159.6 308.15767 L 160.6 308.206416 L 161.6 308.284013 L 162.6 308.314554 L 163.6 308.384068 L 164.6 308.408041 L 165.6 308.436663 L 166.6 308.478456 L 167.6 308.500032 L 168.6 308.51398 L 169.6 308.540702 L 170.6 308.550012 L 171.6 308.562459 L 172.6 308.573514 L 173.6 308.579178 L 174.6 308.583942 L 175.6 308.578394 L 176.6 308.565106 L 177.6 308.557589 L 178.6 308.532804 L 179.6 308.509235 L 180.6 308.473055 L 181.6 308.447093 L 182.6 308.424771 L 183.6 308.356011 L 184.6 308.281476 L 185.6 308.187497 L 186.6 308.136445 L 187.6 308.082511 L 188.6 308.04726 L 189.6 307.941172 L 190.6 307.888908 L 191.6 307.852001 L 192.6 307.82097 L 193.6 307.759815 L 194.6 307.692395 L 195.6 307.643489 L 196.6 307.578297 L 197.6 307.540109 L 198.6 307.498113 L 199.6 307.456096 L 200.6 307.39658 L 201.6 307.28342 L 202.6 307.231169 L 203.6 307.191751 L 204.6 307.14465 L 205.6 307.08787 L 206.6 307.055207 L 207.6 307.019029 L 208.6 306.986939 L 209.6 306.952659 L 210.6 306.894281 L 211.6 306.849096 L 212.6 306.819472 L 213.6 306.769086 L 214.6 306.743889 L 215.6 306.722838 L 216.6 306.68787 L 217.6 306.66358 L 218.6 306.649513 L 219.6 306.630571 L 220.6 306.61491 L 221.6 306.602358 L 222.6 306.596522 L 223.6 306.58964 L 224.6 306.584466 L 225.6 306.586249 L 226.6 306.588974 L 227.6 306.600128 L 228.6 306.628363 L 229.6 306.672151 L 230.6 306.69284 L 231.6 306.733813 L 232.6 306.773888 L 233.6 306.792998 L 234.6 306.815507 L 235.6 306.882158 L 236.6 306.931868 L 237.6 307.005574 L 238.6 307.036888 L 239.6 307.11351 L 240.6 307.151808 L 241.6 307.225925 L 242.6 307.329983 L 243.6 307.399814 L 244.6 307.505048 L 245.6 307.560063 L 246.6 307.683538 L 247.6 307.754097 L 248.6 307.869936 L 249.6 307.920117 L 250.6 307.955721 L 251.6 308.047128 L 252.6 308.100636 L 253.6 308.188544 L 254.6 308.257729 L 255.6 308.304493 L 256.6 308.376537 L 257.6 308.426679 L 258.6 308.444069 L 259.6 308.471072 L 260.6 308.490499 L 261.6 308.509837 L 262.6 308.548086 L 263.6 308.564519 L 264.6 308.572888 L 265.6 308.577207 L 266.6 308.583762 L 267.6 308.581216 L 268.6 308.575757 L 269.6 308.559329 L 270.6 308.527394 L 271.6 308.489414 L 272.6 308.45461 L 273.6 308.391538 L 274.6 308.370111 L 275.6 308.319493 L 276.6 308.294536 L 277.6 308.238902 L 278.6 308.207673 L 279.6 308.157529 L 280.6 308.125036 L 281.6 308.044624 L 282.6 307.975698 L 283.6 307.860001 L 284.6 307.784522 L 285.6 307.668997 L 286.6 307.589513 L 287.6 307.481072 L 288.6 307.441704 L 289.6 307.338836 L 290.6 307.239038 L 291.6 307.193541 L 292.6 307.159219 L 293.6 307.107263 L 294.6 307.067616 L 295.6 307.032102 L 296.6 306.964457 L 297.6 306.925375 L 298.6 306.874894 L 299.6 306.825588 L 300.6 306.774518 L 301.6 306.730279 L 302.6 306.708259 L 303.6 306.692703 L 304.6 306.650256 L 305.6 306.635388 L 306.6 306.61266 L 307.6 306.592344 L 308.6 306.586547 L 309.6 306.584065 L 310.6 306.587122 L 311.6 306.598718 L 312.6 306.615638 L 313.6 306.647299 L 314.6 306.661382 L 315.6 306.714054 L 316.6 306.763143 L 317.6 306.817844 L 318.6 306.862192 L 319.6 306.932184 L 320.6 306.982567 L 321.6 307.036474 L 322.6 307.105913 L 323.6 307.163301 L 324.6 307.213466 L 325.6 307.290628 L 326.6 307.348818 L 327.6 307.409456 L 328.6 307.446657 L 329.6 307.511749 L 330.6 307.616879 L 331.6 307.677181 L 332.6 307.773503 L 333.6 307.805506 L 334.6 307.856523 L 335.6 307.973315 L 336.6 308.008762 L 337.6 308.064642 L 338.6 308.095018 L 339.6 308.183404 L 340.6 308.228168 L 341.6 308.309056 L 342.6 308.369202 L 343.6 308.432288 L 344.6 308.455236 L 345.6 308.471406 L 346.6 308.500335 L 347.6 308.530687 L 348.6 308.543261 L 349.6 308.56814 L 350.6 308.580224 L 351.6 308.583986 L 352.6 308.57955 L 353.6 308.567211 L 354.6 308.552798 L 355.6 308.536725 L 356.6 308.501204 L 357.6 308.48127 L 358.6 308.424681 L 359.6 308.357487 L 360.6 308.330117 L 361.6 308.295969 L 362.6 308.247289 L 363.6 308.199004 L 364.6 308.139927 L 365.6 308.044322 L 366.6 308.001182 L 367.6 307.951334 L 368.6 307.8928 L 369.6 307.845214 L 370.6 307.784086 L 371.6 307.728001 L 372.6 307.65383 L 373.6 307.536592 L 374.6 307.480868 L 375.6 307.372642 L 376.6 307.266492 L 377.6 307.15892 L 378.6 307.124412 L 379.6 307.021105 L 380.6 306.945381 L 381.6 306.905946 L 382.6 306.866562 L 383.6 306.84408 L 384.6 306.788267 L 385.6 306.762215 L 386.6 306.73198 L 387.6 306.681209 L 388.6 306.662558 L 389.6 306.640849 L 390.6 306.628203 L 391.6 306.60921 L 392.6 306.59182 L 393.6 306.584782 L 394.6 306.585806 L 395.6 306.59281 L 396.6 306.60218 L 397.6 306.625578 L 398.6 306.650661 L 399.6 306.66306 L 400.6 306.696153 L 401.6 306.71252 L 402.6 306.730925 L 403.6 306.780062 L 404.6 306.823875 L 405.6 306.86696 L 406.6 306.889901 L 407.6 306.930164 L 408.6 307.015024 L 409.6 307.057416 L 410.6 307.121802 L 411.6 307.166091 L 412.6 307.273937 L 413.6 307.350877 L 414.72 307.387319 L 414.578206 306.584 L 414.653307 305.584 L 414.711902 304.584 L 414.748477 303.584 L 414.860524 302.584 L 414.922209 301.584 L 414.972729 300.584 L 415.071514 299.584 L 415.109536 298.584 L 415.144984 297.584 L 415.236618 296.584 L 415.27989 295.584 L 415.333219 294.584 L 415.366084 293.584 L 415.428978 292.584 L 415.482832 291.584 L 415.539958 290.584 L 415.562048 289.584 L 415.605787 288.584 L 415.652881 287.584 L 415.669728 286.584 L 415.697802 285.584 L 415.708798 284.584 L 415.713367 283.584 L 415.719015 282.584 L 415.719066 281.584 L 415.715976 280.584 L 415.712463 279.584 L 415.706641 278.584 L 415.693789 277.584 L 415.670164 276.584 L 415.65528 275.584 L 415.631708 274.584 L 415.595389 273.584 L 415.563806 272.584 L 415.533913 271.584 L 415.455221 270.584 L 415.41867 269.584 L 415.392947 268.584 L 415.322274 267.584 L 415.231172 266.584 L 415.169215 265.584 L 415.135602 264.584 L 415.101102 263.584 L 415.003662 262.584 L 414.956072 261.584 L 414.924566 260.584 L 414.880881 259.584 L 414.810712 258.584 L 414.760845 257.584 L 414.726168 256.584 L 414.61652 255.584 L 414.583049 254.584 L 414.545707 253.584 L 414.465462 252.584 L 414.426968 251.584 L 414.385191 250.584 L 414.342766 249.584 L 414.233038 248.584 L 414.144753 247.584 L 414.070107 246.584 L 413.98165 245.584 L 413.907588 244.584 L 413.858423 243.584 L 413.802806 242.584 L 413.768106 241.584 L 413.756235 240.584 L 413.734012 239.584 L 413.722033 238.584 L 413.720281 237.584 L 413.725698 236.584 L 413.741896 235.584 L 413.758396 234.584 L 413.789579 233.584 L 413.802944 232.584 L 413.832587 231.584 L 413.89561 230.584 L 413.944931 229.584 L 413.99102 228.584 L 414.073247 227.584 L 414.11915 226.584 L 414.153475 225.584 L 414.207014 224.584 L 414.295901 223.584 L 414.327039 222.584 L 414.435088 221.584 L 414.54716 220.584 L 414.582598 219.584 L 414.667384 218.584 L 414.732991 217.584 L 414.835045 216.584 L 414.95126 215.584 L 414.991951 214.584 L 415.03304 213.584 L 415.069681 212.584 L 415.110677 211.584 L 415.186746 210.584 L 415.262812 209.584 L 415.2935 208.584 L 415.319991 207.584 L 415.376572 206.584 L 415.421088 205.584 L 415.451106 204.584 L 415.478162 203.584 L 415.520727 202.584 L 415.573592 201.584 L 415.604513 200.584 L 415.630788 199.584 L 415.645721 198.584 L 415.67601 197.584 L 415.697339 196.584 L 415.714228 195.584 L 415.718943 194.584 L 415.719553 193.584 L 415.717507 192.584 L 415.711646 191.584 L 415.692999 190.584 L 415.660942 189.584 L 415.614502 188.584 L 415.572556 187.584 L 415.505851 186.584 L 415.436785 185.584 L 415.38941 184.584 L 415.337891 183.584 L 415.298191 182.584 L 415.228771 181.584 L 415.16224 180.584 L 415.053331 179.584 L 414.988083 178.584 L 414.879875 177.584 L 414.818871 176.584 L 414.770186 175.584 L 414.693952 174.584 L 414.634421 173.584 L 414.559793 172.584 L 414.440966 171.584 L 414.343021 170.584 L 414.263973 169.584 L 414.218226 168.584 L 414.190954 167.584 L 414.147292 166.584 L 414.098708 165.584 L 414.066974 164.584 L 413.986744 163.584 L 413.920251 162.584 L 413.896226 161.584 L 413.835727 160.584 L 413.813495 159.584 L 413.794895 158.584 L 413.765569 157.584 L 413.749868 156.584 L 413.741569 155.584 L 413.731333 154.584 L 413.72099 153.584 L 413.721668 152.584 L 413.725448 151.584 L 413.741889 150.584 L 413.754023 149.584 L 413.764618 148.584 L 413.795995 147.584 L 413.821768 146.584 L 413.853177 145.584 L 413.875986 144.584 L 413.89358 143.584 L 413.943392 142.584 L 413.991052 141.584 L 414.062761 140.584 L 414.118524 139.584 L 414.144722 138.584 L 414.17549 137.584 L 414.265248 136.584 L 414.350042 135.584 L 414.415636 134.584 L 414.461461 133.584 L 414.504458 132.584 L 414.565971 131.584 L 414.665796 130.584 L 414.710226 129.584 L 414.760276 128.584 L 414.882117 127.584 L 414.94181 126.584 L 414.973376 125.584 L 415.005719 124.584 L 415.060279 123.584 L 415.102779 122.584 L 415.154251 121.584 L 415.242636 120.584 L 415.276833 119.584 L 415.320767 118.584 L 415.38448 117.584 L 415.459677 116.584 L 415.488491 115.584 L 415.530695 114.584 L 415.57328 113.584 L 415.590172 112.584 L 415.612653 111.584 L 415.65499 110.584 L 415.68495 109.584 L 415.703583 108.584 L 415.713375 107.584 L 415.717138 106.584 L 415.719976 105.584 L 415.718227 104.584 L 415.708871 103.584 L 415.698174 102.584 L 415.688304 101.584 L 415.669446 100.584 L 415.639107 99.584 L 415.600716 98.584 L 415.54123 97.584 L 415.497941 96.584 L 415.437203 95.584 L 415.353129 94.584 L 415.304836 93.584 L 415.261259 92.584 L 415.234378 91.584 L 415.202448 90.584 L 415.135256 89.584 L 415.054435 88.584 L 414.97889 87.584 L 414.93516 86.584 L 414.855265 85.584 L 414.793786 84.584 L 414.730161 83.584 L 414.622912 82.584 L 414.504202 81.584 L 414.462296 80.584 L 414.419342 79.584 L 414.357143 78.584 L 414.327006 77.584 L 414.294488 76.584 L 414.242553 75.584 L 414.137003 74.584 L 414.088557 73.584 L 414.042233 72.584 L 414.008417 71.584 L 413.96054 70.584 L 413.905662 69.584 L 413.881751 68.584 L 413.855714 67.584 L 413.799597 66.584 L 413.785723 65.584 L 413.759689 64.584 L 413.732943 63.584 L 413.725197 62.584 L 413.720044 61.584 L 413.726242 60.584 L 413.732549 59.584 L 413.74013 58.584 L 413.767636 57.584 L 413.811869 56.584 L 413.841407 55.584 L 413.883254 54.584 L 413.942428 53.584 L 413.965138 52.584 L 414.00177 51.584 L 414.058558 50.584 L 414.083728 49.584 L 414.166424 48.584 L 414.253356 47.584 L 414.30404 46.584 L 414.341434 45.584 L 414.425814 44.584 L 414.460325 43.584 L 414.552316 42.584 L 414.639341 41.472 L 413.72 41.429519 L 412.72 41.39165 L 411.72 41.344175 L 410.72 41.238649 L 409.72 41.141188 L 408.72 41.064551 L 407.72 41.032624 L 406.72 40.978384 L 405.72 40.939533 L 404.72 40.865828 L 403.72 40.833832 L 402.72 40.777293 L 401.72 40.741177 L 400.72 40.672575 L 399.72 40.641159 L 398.72 40.586492 L 397.72 40.567721 L 396.72 40.522092 L 395.72 40.499189 L 394.72 40.490648 L 393.72 40.483307 L 392.72 40.477012 L 391.72 40.473835 L 390.72 40.472249 L 389.72 40.473712 L 388.72 40.486666 L 387.72 40.501288 L 386.72 40.513144 L 385.72 40.531169 L 384.72 40.551547 L 383.72 40.574946 L 382.72 40.589855 L 381.72 40.644569 L 380.72 40.678166 L 379.72 40.740862 L 378.72 40.768237 L 377.72 40.812217 L 376.72 40.891164 L 375.72 40.948692 L 374.72 40.998671 L 373.72 41.070655 L 372.72 41.107187 L 371.72 41.1755 L 370.72 41.263706 L 369.72 41.385053 L 368.72 41.450734 L 367.72 41.484352 L 366.72 41.548629 L 365.72 41.5946 L 364.72 41.666757 L 363.72 41.706583 L 362.72 41.749213 L 361.72 41.855172 L 360.72 41.907957 L 359.72 41.987234 L 358.72 42.029638 L 357.72 42.061904 L 356.72 42.09677 L 355.72 42.139428 L 354.72 42.171001 L 353.72 42.23858 L 352.72 42.275465 L 351.72 42.303421 L 350.72 42.324269 L 349.72 42.349882 L 348.72 42.3875 L 347.72 42.402342 L 346.72 42.427072 L 345.72 42.445302 L 344.72 42.456709 L 343.72 42.462344 L 342.72 42.467098 L 341.72 42.471707 L 340.72 42.470034 L 339.72 42.464252 L 338.72 42.444256 L 337.72 42.432604 L 336.72 42.421615 L 335.72 42.408648 L 334.72 42.358234 L 333.72 42.337412 L 332.72 42.309465 L 331.72 42.25272 L 330.72 42.230076 L 329.72 42.178673 L 328.72 42.137537 L 327.72 42.054768 L 326.72 42.006308 L 325.72 41.954881 L 324.72 41.903721 L 323.72 41.836422 L 322.72 41.803268 L 321.72 41.73721 L 320.72 41.681025 L 319.72 41.619746 L 318.72 41.579763 L 317.72 41.48334 L 316.72 41.37158 L 315.72 41.332661 L 314.72 41.234812 L 313.72 41.200158 L 312.72 41.116476 L 311.72 41.06597 L 310.72 40.996927 L 309.72 40.895824 L 308.72 40.843378 L 307.72 40.75407 L 306.72 40.689062 L 305.72 40.647517 L 304.72 40.605177 L 303.72 40.583157 L 302.72 40.54567 L 301.72 40.528418 L 300.72 40.50501 L 299.72 40.496443 L 298.72 40.487354 L 297.72 40.480286 L 296.72 40.473259 L 295.72 40.472151 L 294.72 40.472137 L 293.72 40.474811 L 292.72 40.477837 L 291.72 40.483304 L 290.72 40.503299 L 289.72 40.51527 L 288.72 40.542389 L 287.72 40.569401 L 286.72 40.596567 L 285.72 40.651042 L 284.72 40.680658 L 283.72 40.722414 L 282.72 40.795523 L 281.72 40.838961 L 280.72 40.909652 L 279.72 40.948059 L 278.72 41.008398 L 277.72 41.039153 L 276.72 41.069651 L 275.72 41.128561 L 274.72 41.171738 L 273.72 41.21335 L 272.72 41.262465 L 271.72 41.327552 L 270.72 41.393947 L 269.72 41.51871 L 268.72 41.562525 L 267.72 41.616853 L 266.72 41.723557 L 265.72 41.766057 L 264.72 41.803551 L 263.72 41.893047 L 262.72 41.95027 L 261.72 42.019913 L 260.72 42.068932 L 259.72 42.124877 L 258.72 42.172002 L 257.72 42.21089 L 256.72 42.264582 L 255.72 42.310153 L 254.72 42.34709 L 253.72 42.369166 L 252.72 42.402049 L 251.72 42.431769 L 250.72 42.444319 L 249.72 42.456218 L 248.72 42.461336 L 247.72 42.469225 L 246.72 42.471856 L 245.72 42.471058 L 244.72 42.467817 L 243.72 42.452679 L 242.72 42.445742 L 241.72 42.429365 L 240.72 42.410952 L 239.72 42.38136 L 238.72 42.359278 L 237.72 42.301584 L 236.72 42.276393 L 235.72 42.20808 L 234.72 42.160954 L 233.72 42.123606 L 232.72 42.068397 L 231.72 41.978966 L 230.72 41.875856 L 229.72 41.821882 L 228.72 41.791162 L 227.72 41.735621 L 226.72 41.697886 L 225.72 41.629632 L 224.72 41.593803 L 223.72 41.524019 L 222.72 41.464725 L 221.72 41.426118 L 220.72 41.392122 L 219.72 41.349542 L 218.72 41.302893 L 217.72 41.248327 L 216.72 41.162426 L 215.72 41.11575 L 214.72 41.058435 L 213.72 41.028021 L 212.72 40.94297 L 211.72 40.909295 L 210.72 40.821371 L 209.72 40.766386 L 208.72 40.727697 L 207.72 40.657666 L 206.72 40.62722 L 205.72 40.569495 L 204.72 40.552351 L 203.72 40.527616 L 202.72 40.512116 L 201.72 40.488664 L 200.72 40.48185 L 199.72 40.477917 L 198.72 40.474185 L 197.72 40.472152 L 196.72 40.480538 L 195.72 40.496924 L 194.72 40.523194 L 193.72 40.536523 L 192.72 40.566477 L 191.72 40.600728 L 190.72 40.621398 L 189.72 40.66241 L 188.72 40.735728 L 187.72 40.758946 L 186.72 40.799312 L 185.72 40.826563 L 184.72 40.907101 L 183.72 40.960579 L 182.72 41.03915 L 181.72 41.087618 L 180.72 41.201648 L 179.72 41.302333 L 178.72 41.386757 L 177.72 41.478297 L 176.72 41.58071 L 175.72 41.621518 L 174.72 41.664661 L 173.72 41.703962 L 172.72 41.737385 L 171.72 41.780493 L 170.72 41.886072 L 169.72 41.941773 L 168.72 42.0471 L 167.72 42.144097 L 166.72 42.167117 L 165.72 42.194104 L 164.72 42.224205 L 163.72 42.297447 L 162.72 42.334839 L 161.72 42.369798 L 160.72 42.388374 L 159.72 42.41888 L 158.72 42.431092 L 157.72 42.440868 L 156.72 42.450437 L 155.72 42.458646 L 154.72 42.469922 L 153.72 42.471784 L 152.72 42.465482 L 151.72 42.459469 L 150.72 42.454012 L 149.72 42.43382 L 148.72 42.423931 L 147.72 42.396178 L 146.72 42.377171 L 145.72 42.361772 L 144.72 42.332507 L 143.72 42.268703 L 142.72 42.21965 L 141.72 42.149461 L 140.72 42.120352 L 139.72 42.060782 L 138.72 42.013833 L 137.72 41.962711 L 136.72 41.908658 L 135.72 41.826971 L 134.72 41.748314 L 133.72 41.711654 L 132.72 41.59 L 131.72 41.511058 L 130.72 41.446567 L 129.72 41.400939 L 128.72 41.28529 L 127.72 41.237015 L 126.72 41.201492 L 125.72 41.157914 L 124.72 41.122138 L 123.72 41.051313 L 122.72 41.014909 L 121.72 40.917433 L 120.72 40.848369 L 119.72 40.782403 L 118.72 40.717873 L 117.72 40.694451 L 116.72 40.667046 L 115.72 40.618552 L 114.72 40.588559 L 113.72 40.556021 L 112.72 40.541278 L 111.72 40.527738 L 110.72 40.504303 L 109.72 40.491823 L 108.72 40.484685 L 107.72 40.479087 L 106.72 40.473481 L 105.72 40.472 L 104.72 40.477993 L 103.72 40.483958 L 102.72 40.49547 L 101.72 40.519277 L 100.72 40.52941 L 99.72 40.571368 L 98.72 40.61344 L 97.72 40.644656 L 96.72 40.714514 L 95.72 40.75877 L 94.72 40.84124 L 93.72 40.929427 L 92.72 40.974347 L 91.72 41.070077 L 90.72 41.142181 L 89.72 41.237171 L 88.72 41.293545 L 87.72 41.337742 L 86.72 41.393558 L 85.72 41.433496 L 84.72 41.508947 L 83.72 41.566942 L 82.72 41.604129 L 81.72 41.662656 L 80.72 41.765433 L 79.72 41.82216 L 78.72 41.893165 L 77.72 41.954934 L 76.72 41.992397 L 75.72 42.027683 L 74.72 42.071101 L 73.72 42.11296 L 72.72 42.140583 L 71.72 42.191698 L 70.72 42.225234 L 69.72 42.287297 L 68.72 42.306939 L 67.72 42.368712 L 66.72 42.391191 L 65.72 42.411414 L 64.72 42.432103 L 63.72 42.45853 L 62.72 42.469487 L 61.72 42.471269 L 60.72 42.468641 L 59.72 42.462091 L 58.72 42.440128 L 57.6 42.401128 L 58.508845 42.472 L 58.492196 43.472 L 58.430573 44.472 L 58.401989 45.472 L 58.378481 46.472 L 58.334033 47.472 L 58.30807 48.472 L 58.25771 49.472 L 58.181318 50.472 L 58.153797 51.472 L 58.121939 52.472 L 58.086315 53.472 L 57.998542 54.472 L 57.901531 55.472 L 57.821578 56.472 L 57.703903 57.472 L 57.631909 58.472 L 57.527743 59.472 L 57.416434 60.472 L 57.321012 61.472 L 57.226115 62.472 L 57.159096 63.472 L 57.098211 64.472 L 57.05375 65.472 L 57.018079 66.472 L 56.938783 67.472 L 56.908528 68.472 L 56.834884 69.472 L 56.802439 70.472 L 56.757912 71.472 L 56.736656 72.472 L 56.708304 73.472 L 56.679978 74.472 L 56.645645 75.472 L 56.632329 76.472 L 56.615537 77.472 L 56.604993 78.472 L 56.601874 79.472 L 56.600038 80.472 L 56.605027 81.472 L 56.610475 82.472 L 56.62462 83.472 L 56.659254 84.472 L 56.678281 85.472 L 56.720881 86.472 L 56.738986 87.472 L 56.783389 88.472 L 56.805819 89.472 L 56.846087 90.472 L 56.878592 91.472 L 56.941903 92.472 L 57.030413 93.472 L 57.116883 94.472 L 57.196518 95.472 L 57.250304 96.472 L 57.310415 97.472 L 57.381456 98.472 L 57.501577 99.472 L 57.606039 100.472 L 57.716842 101.472 L 57.770115 102.472 L 57.843365 103.472 L 57.881948 104.472 L 57.957711 105.472 L 58.035272 106.472 L 58.121412 107.472 L 58.148855 108.472 L 58.244831 109.472 L 58.320941 110.472 L 58.371105 111.472 L 58.425458 112.472 L 58.453129 113.472 L 58.489151 114.472 L 58.520712 115.472 L 58.538819 116.472 L 58.555558 117.472 L 58.572565 118.472 L 58.589619 119.472 L 58.59403 120.472 L 58.598289 121.472 L 58.599886 122.472 L 58.598359 123.472 L 58.595935 124.472 L 58.592476 125.472 L 58.582211 126.472 L 58.562483 127.472 L 58.550784 128.472 L 58.50804 129.472 L 58.48236 130.472 L 58.438178 131.472 L 58.382063 132.472 L 58.325365 133.472 L 58.293505 134.472 L 58.256796 135.472 L 58.228663 136.472 L 58.172864 137.472 L 58.138147 138.472 L 58.06646 139.472 L 58.010402 140.472 L 57.928747 141.472 L 57.873173 142.472 L 57.788865 143.472 L 57.74624 144.472 L 57.655234 145.472 L 57.594949 146.472 L 57.489872 147.472 L 57.425687 148.472 L 57.346491 149.472 L 57.280264 150.472 L 57.225988 151.472 L 57.192861 152.472 L 57.136147 153.472 L 57.09259 154.472 L 56.995347 155.472 L 56.921401 156.472 L 56.859607 157.472 L 56.831192 158.472 L 56.805858 159.472 L 56.739603 160.472 L 56.696586 161.472 L 56.668079 162.472 L 56.656085 163.472 L 56.642011 164.472 L 56.631183 165.472 L 56.615885 166.472 L 56.606029 167.472 L 56.600216 168.472 L 56.601051 169.472 L 56.603013 170.472 L 56.606621 171.472 L 56.623932 172.472 L 56.633663 173.472 L 56.667693 174.472 L 56.692764 175.472 L 56.731461 176.472 L 56.797395 177.472 L 56.838383 178.472 L 56.913224 179.472 L 56.945151 180.472 L 56.969365 181.472 L 56.995185 182.472 L 57.054225 183.472 L 57.108937 184.472 L 57.215139 185.472 L 57.295415 186.472 L 57.412157 187.472 L 57.51212 188.472 L 57.564434 189.472 L 57.603007 190.472 L 57.639368 191.472 L 57.760354 192.472 L 57.791539 193.472 L 57.827915 194.472 L 57.890066 195.472 L 57.978077 196.472 L 58.02247 197.472 L 58.070988 198.472 L 58.169778 199.472 L 58.211246 200.472 L 58.253898 201.472 L 58.318748 202.472 L 58.385183 203.472 L 58.405272 204.472 L 58.429751 205.472 L 58.470359 206.472 L 58.494905 207.472 L 58.511852 208.472 L 58.542871 209.472 L 58.565923 210.472 L 58.585366 211.472 L 58.592773 212.472 L 58.596995 213.472 L 58.599656 214.472 L 58.599239 215.472 L 58.593894 216.472 L 58.584738 217.472 L 58.572213 218.472 L 58.545446 219.472 L 58.51655 220.472 L 58.46624 221.472 L 58.437897 222.472 L 58.382994 223.472 L 58.345187 224.472 L 58.292498 225.472 L 58.262794 226.472 L 58.231793 227.472 L 58.201321 228.472 L 58.159084 229.472 L 58.131062 230.472 L 58.033515 231.472 L 57.95707 232.472 L 57.901773 233.472 L 57.820903 234.472 L 57.743522 235.472 L 57.662112 236.472 L 57.605147 237.472 L 57.482034 238.472 L 57.450465 239.472 L 57.383234 240.472 L 57.304942 241.472 L 57.212389 242.472 L 57.178235 243.472 L 57.147321 244.472 L 57.096996 245.472 L 57.052178 246.472 L 57.011177 247.472 L 56.981322 248.472 L 56.936474 249.472 L 56.85321 250.472 L 56.83115 251.472 L 56.787033 252.472 L 56.766871 253.472 L 56.706749 254.472 L 56.66452 255.472 L 56.641263 256.472 L 56.623268 257.472 L 56.616266 258.472 L 56.604027 259.472 L 56.600558 260.472 L 56.601741 261.472 L 56.605916 262.472 L 56.619646 263.472 L 56.627297 264.472 L 56.641737 265.472 L 56.672389 266.472 L 56.697078 267.472 L 56.717325 268.472 L 56.735798 269.472 L 56.754752 270.472 L 56.789358 271.472 L 56.856641 272.472 L 56.904869 273.472 L 56.934251 274.472 L 56.966094 275.472 L 57.044318 276.472 L 57.14353 277.472 L 57.187424 278.472 L 57.298184 279.472 L 57.351957 280.472 L 57.410165 281.472 L 57.446342 282.472 L 57.501133 283.472 L 57.584084 284.472 L 57.631754 285.472 L 57.720599 286.472 L 57.768247 287.472 L 57.848469 288.472 L 57.937896 289.472 L 57.982122 290.472 L 58.041179 291.472 L 58.139628 292.472 L 58.17467 293.472 L 58.220434 294.472 L 58.273635 295.472 L 58.309483 296.472 L 58.351738 297.472 L 58.393097 298.472 L 58.420445 299.472 L 58.48147 300.472 L 58.504483 301.472 L 58.519261 302.472 L 58.534284 303.472 L 58.547208 304.472 L 58.579534 305.472 L 58.596802 306.472 L 58.599844 307.584 z " + style="fill: #ffffff" + id="path4" /> + </g> + <g + id="matplotlib.axis_1"> + <g + id="text_1"> + <path + d="M 171.004219 322.974312 C 172.165781 322.974312 172.165781 320.854625 172.165781 320.143687 C 172.165781 319.15275 171.995156 318.168375 171.995156 317.162125 C 171.995156 316.013688 172.124219 314.86525 172.124219 313.703688 C 172.124219 313.581187 172.124219 313.095562 172.084844 312.631813 C 172.043281 312.200875 171.940469 311.708687 171.686719 311.708687 C 171.181406 311.708687 170.647656 311.885875 170.566719 312.487437 C 170.457344 313.34275 170.483594 314.279 170.483594 315.132125 L 170.498906 317.05275 C 170.512031 318.017437 170.737344 319.014937 170.737344 319.99275 C 170.737344 320.005875 170.737344 320.124 170.724219 320.218062 C 170.724219 320.314312 170.724219 320.410563 170.682656 320.410563 C 170.586406 320.410563 170.437656 320.060563 170.299844 319.71275 C 170.164219 319.349625 170.032969 318.966813 170.006719 318.885875 C 169.540781 317.599625 166.957344 312.568375 165.487344 312.568375 C 164.564219 312.568375 164.564219 314.559 164.564219 315.105875 C 164.564219 317.286812 164.673594 319.480875 164.673594 321.661812 C 164.673594 322.167125 165.139531 322.987437 165.725781 322.987437 C 166.382031 322.987437 166.436719 321.819313 166.436719 321.353375 C 166.436719 320.349312 166.287969 319.343062 166.287969 318.339 C 166.287969 317.389625 166.075781 316.444625 166.075781 315.482125 C 166.075781 315.466813 166.047344 315.208687 166.102031 315.208687 C 166.465156 315.208687 168.427344 319.391188 168.707344 320.034312 C 169.028906 320.8065 170.000156 322.974312 171.004219 322.974312 z M 174.988477 316.096812 C 174.367227 316.424937 174.209727 317.450875 174.058789 318.297438 C 173.691289 320.375563 173.697852 323.05525 176.261602 322.794938 C 177.230664 322.700875 178.256602 322.186812 178.845039 321.456187 C 179.144727 321.0865 179.433477 320.506813 179.520977 320.054 C 179.733164 318.966813 179.426914 317.881813 179.234414 317.05275 C 179.166602 316.766188 179.118477 316.4665 178.871289 316.383375 C 178.652539 316.309 178.236914 316.444625 178.147227 316.61525 C 178.005039 316.888688 178.324414 317.5865 178.407539 317.96275 C 178.510352 318.448375 178.571602 319.104625 178.536602 319.6165 C 178.455664 320.74525 177.410039 321.661812 176.261602 321.764625 C 175.988164 321.790875 175.625039 321.810563 175.406289 321.709938 C 175.132852 321.578688 174.997227 321.108375 174.942539 320.751812 C 174.675664 318.934 175.338477 317.846812 175.480664 316.357125 C 175.371289 316.21275 175.152539 316.17775 174.988477 316.096812 z M 186.200781 322.399 C 186.467656 321.749312 186.555156 320.764937 186.686406 319.83525 C 186.808906 318.947125 186.924844 317.969313 187.342656 317.444313 C 187.513281 317.232125 187.944219 316.904 188.278906 316.93025 C 188.838906 316.971812 189.234844 317.763688 189.221719 318.413375 C 189.215156 318.721812 189.051094 319.207438 188.906719 319.609938 C 188.703281 320.191813 188.462656 320.896187 188.510781 321.626812 C 188.539219 322.003062 188.729531 322.61775 189.051094 322.794938 C 189.385781 322.980875 189.864844 322.685563 189.932656 322.37275 C 189.993906 322.09275 189.652656 321.893687 189.617656 321.572125 C 189.597969 321.408062 189.639531 321.14775 189.672344 320.977125 C 189.823281 320.191813 190.295781 319.268687 190.357031 318.4965 C 190.411719 317.853375 190.157969 317.177437 189.851719 316.733375 C 189.420781 316.1165 188.639844 315.598062 187.710156 315.878062 C 187.130469 316.05525 186.767344 316.418375 186.342969 316.958687 C 186.310156 316.68525 186.097969 316.376812 185.914219 316.158062 C 185.120156 315.61775 183.794531 316.035563 183.241094 316.704937 C 183.061719 316.917125 183.007031 317.170875 182.810156 317.299937 C 182.823281 316.998063 182.816719 316.05525 182.530156 315.904313 C 182.331094 315.803688 182.022656 315.994 181.757969 316.022438 C 181.523906 316.389937 181.668281 316.875563 181.703281 317.389625 C 181.784219 318.52275 181.893594 319.979625 181.812656 321.06025 C 181.777656 321.482438 181.539219 321.919938 181.585156 322.256813 C 181.613594 322.466813 181.845469 322.630875 181.928594 322.768687 C 182.398906 322.93275 182.672344 322.685563 182.871406 322.256813 C 182.952344 320.5265 183.308906 318.831187 184.032969 317.499 C 184.341406 317.28025 184.586406 317.013375 185.148594 317.046187 C 185.640781 318.255875 184.975781 320.375563 185.148594 321.858687 C 185.181406 322.18025 185.380469 322.37275 185.516094 322.514937 C 185.782969 322.5215 185.995156 322.453688 186.200781 322.399 z M 192.483555 317.334938 C 192.49668 316.534312 192.55793 315.173687 192.483555 314.224312 C 192.455117 313.889625 192.40043 313.137125 192.100742 313.075875 C 191.92793 313.040875 191.763867 313.178688 191.615117 313.178688 C 191.28043 314.018687 191.62168 315.420875 191.512305 316.77275 C 191.435742 317.689312 191.36793 318.654 191.409492 319.55525 C 191.457617 320.568062 191.483867 322.105875 192.249492 321.90025 C 192.448555 321.845562 192.61918 321.810563 192.686992 321.62025 C 193.645117 322.193375 195.272617 322.18025 196.106055 321.491188 C 196.33793 321.298687 196.447305 321.053688 196.666055 320.880875 C 196.974492 320.191813 197.46668 319.200875 197.27418 318.249312 C 197.18668 317.80525 196.95918 317.422438 196.788555 317.05275 C 196.270117 316.499312 195.791055 316.048687 194.826367 316.035563 C 193.719492 316.022438 192.966992 316.704937 192.483555 317.334938 z M 194.34293 321.06025 C 193.699805 321.066813 193.17918 320.799937 192.763555 320.471812 C 192.74168 318.796187 193.207617 317.464 194.417305 317.081187 C 194.732305 316.978375 195.327305 317.100875 195.546055 317.232125 C 196.701055 317.9365 196.318242 320.178688 195.285742 320.826188 C 195.12168 320.929 194.58793 321.06025 194.34293 321.06025 z M 199.577617 319.522438 C 200.24918 319.631813 201.041055 319.535563 201.957617 319.459 C 202.955117 319.378062 203.816992 319.522438 204.21293 318.947125 C 204.547617 317.921187 204.261055 316.698375 203.49543 316.1165 C 202.941992 315.694313 201.935742 315.412125 201.170117 315.604625 C 200.658242 315.733687 199.831367 316.274 199.393867 316.814312 C 198.608555 317.779 197.998242 319.67775 198.615117 320.964 C 198.96293 321.517437 199.27793 321.983375 199.844492 322.289625 C 200.822305 322.823375 201.951055 322.563063 202.858867 322.263375 C 203.289805 322.119 203.77543 321.954937 204.061992 321.723063 C 204.241367 321.578688 204.425117 321.292125 204.363867 321.0865 C 204.315742 320.909312 203.904492 320.539625 203.646367 320.546187 C 203.421055 320.55275 203.24168 320.8415 203.009805 320.964 C 202.395117 321.298687 201.27293 321.668375 200.481055 321.333687 C 199.83793 321.06025 199.551367 320.355875 199.577617 319.522438 z M 202.55918 316.93025 C 202.86543 317.094313 203.235117 317.599625 203.160742 318.229625 C 201.99918 318.24275 200.96668 318.345562 199.818242 318.43525 C 200.172617 317.553688 201.294805 316.260875 202.55918 316.93025 z M 210.160742 316.827437 C 210.138867 316.978375 210.228555 317.019938 210.270117 317.107438 C 210.93293 317.56025 211.460117 317.068062 211.27418 316.376812 C 211.096992 316.103375 210.83668 315.913063 210.49543 315.794938 C 209.27918 315.385875 207.069805 315.768687 206.529492 316.575875 C 206.406992 316.383375 205.86668 316.350563 205.669805 316.49275 C 205.545117 316.582438 205.512305 316.882125 205.49918 317.135875 C 205.457617 317.827125 205.553867 318.702125 205.49918 319.364937 C 205.396367 320.607438 205.396367 321.797438 205.52543 322.549937 C 205.64793 322.679 205.792305 322.781813 205.943242 322.884625 C 206.14668 322.8365 206.133555 322.843062 206.36543 322.858375 C 206.483555 322.762125 206.564492 322.630875 206.673867 322.5215 C 206.577617 321.86525 206.667305 321.250563 206.728555 320.513375 C 206.824805 319.349625 206.818242 318.107125 207.31043 317.299937 C 207.850742 316.724625 209.128242 316.656813 210.160742 316.827437 z M 219.08793 315.2415 C 218.444805 315.269937 217.768867 315.733687 217.412305 316.096812 C 217.27668 316.232438 217.15418 316.479625 216.990117 316.691813 C 216.537305 317.286812 216.108555 318.271187 215.99918 319.124312 C 215.813242 320.546187 216.333867 321.954937 217.125742 322.475563 C 217.27668 322.569625 217.639805 322.749 217.865117 322.781813 C 218.569492 322.884625 219.457617 322.536812 219.96293 322.21525 C 220.58418 321.819313 221.220742 321.128062 221.49418 320.484938 C 221.999492 319.303688 221.780742 317.730875 221.268867 316.801188 C 221.098242 316.49275 220.844492 316.260875 220.58418 316.007125 C 220.14668 315.584938 219.70918 315.21525 219.08793 315.2415 z M 217.585117 317.737437 C 217.781992 317.374312 218.521367 316.37025 219.08793 316.350563 C 219.094492 316.350563 219.116367 316.309 219.142617 316.322125 C 220.02418 316.704937 220.673867 317.676188 220.673867 319.043375 C 220.673867 319.809 220.256055 320.498063 219.792305 320.944313 C 219.381055 321.34025 218.547617 321.784312 218.007305 321.6465 C 217.65293 321.559 217.412305 321.195875 217.296367 320.915875 C 216.928867 320.02775 217.132305 318.551188 217.585117 317.737437 z M 226.116367 312.8965 C 226.538555 313.082437 226.99793 313.334 227.483555 313.581187 C 227.912305 313.799937 228.522617 314.237437 228.883555 314.163063 C 229.178867 314.099625 229.533242 313.404 229.436992 313.191812 C 229.288242 312.87025 228.365117 312.644937 227.975742 312.439312 C 227.345742 312.111187 226.888555 311.796187 226.409492 311.59275 C 225.96543 311.55775 225.534492 311.647438 225.206367 311.885875 C 224.43418 312.828688 224.33793 314.237437 224.228555 315.727125 C 223.292305 315.646187 222.636055 315.823375 222.92918 316.834 C 223.169805 317.107438 223.83918 316.936812 224.228555 317.0615 C 224.167305 318.345562 224.427617 319.343062 224.427617 320.539625 C 224.427617 321.388375 224.228555 322.289625 224.65293 322.788375 C 224.913242 322.788375 225.18668 322.803688 225.40543 322.755562 C 225.521367 322.5915 225.637305 322.392437 225.663555 322.202125 C 225.910742 320.629313 225.425117 318.693375 225.569492 317.129313 C 226.18418 317.013375 227.091992 317.081187 227.448555 316.669938 C 227.74168 316.33525 227.544805 315.891188 227.256055 315.694313 C 226.86668 315.420875 226.696055 315.61775 226.348242 315.727125 C 226.094492 315.81025 225.84293 315.794938 225.534492 315.858375 C 225.541055 315.324625 225.602305 314.784312 225.691992 314.263688 C 225.779492 313.758375 225.74668 313.178688 226.116367 312.8965 z M 237.258125 314.928688 C 237.496562 313.915875 237.721875 312.706187 237.518438 311.728375 C 237.299688 311.584 236.971563 311.551187 236.83375 311.632125 C 236.129375 312.049937 236.245312 314.073375 235.952187 314.928688 C 235.254375 315.029313 234.504062 314.764625 233.99 315.029313 C 233.941875 315.30275 233.784375 315.788375 233.99 316.007125 C 234.407812 316.241188 235.077187 316.219313 235.720312 316.232438 C 235.691875 316.7115 235.5825 317.422438 235.55625 317.9365 C 235.473125 319.548687 235.466562 321.600563 236.376562 322.405562 C 237.010937 322.974312 238.249062 322.81025 239.0825 322.536812 C 239.3625 322.447125 239.690625 322.399 239.835 322.2765 C 240.121562 322.029313 239.93125 321.469313 239.73875 321.202437 C 239.089062 320.977125 238.010625 321.825875 237.354375 321.49775 C 236.95625 321.298687 236.901562 320.382125 236.862188 319.828688 C 236.779062 318.673687 236.916875 317.232125 237.02625 316.232438 C 237.84 316.1865 238.638437 316.3965 239.506875 316.267437 C 239.786875 316.042125 239.684062 315.427437 239.506875 315.125563 C 238.850625 314.968062 237.98875 315.009625 237.258125 314.928688 z M 245.728125 316.827437 C 245.70625 316.978375 245.795937 317.019938 245.8375 317.107438 C 246.500313 317.56025 247.0275 317.068062 246.841562 316.376812 C 246.664375 316.103375 246.404062 315.913063 246.062813 315.794938 C 244.846563 315.385875 242.637187 315.768687 242.096875 316.575875 C 241.974375 316.383375 241.434062 316.350563 241.237188 316.49275 C 241.1125 316.582438 241.079687 316.882125 241.066562 317.135875 C 241.025 317.827125 241.12125 318.702125 241.066562 319.364937 C 240.96375 320.607438 240.96375 321.797438 241.092812 322.549937 C 241.215312 322.679 241.359688 322.781813 241.510625 322.884625 C 241.714062 322.8365 241.700937 322.843062 241.932812 322.858375 C 242.050937 322.762125 242.131875 322.630875 242.24125 322.5215 C 242.145 321.86525 242.234688 321.250563 242.295937 320.513375 C 242.392187 319.349625 242.385625 318.107125 242.877813 317.299937 C 243.418125 316.724625 244.695625 316.656813 245.728125 316.827437 z M 253.574687 317.162125 C 253.526562 317.0615 253.349375 317.100875 253.246562 317.05275 C 252.844063 316.514625 252.214062 316.068375 251.284375 316.096812 C 249.015938 316.158062 247.80625 318.68025 247.812813 320.880875 C 247.812813 321.257125 247.887187 321.755875 248.1125 322.077437 C 248.394687 322.475563 248.816875 322.685563 249.234688 322.816813 C 251.155312 322.823375 251.98875 321.749312 252.8375 320.690562 C 253.104375 321.62025 253.506875 323.029 254.532812 322.762125 C 254.887187 322.482125 254.812813 321.764625 254.36875 321.694625 C 254.005625 321.018687 253.754062 320.069313 253.684062 319.104625 C 253.644687 318.448375 253.8 317.750563 253.574687 317.162125 z M 250.328438 317.435563 C 250.984688 317.019938 252.065313 317.074625 252.564062 317.573375 C 252.49625 317.9365 252.605625 318.428688 252.564062 318.748063 C 252.474375 319.452437 251.86625 320.327437 251.284375 320.90275 C 250.83375 321.353375 249.761875 322.09275 249.015938 321.530562 C 248.626562 320.089 249.260937 318.12025 250.328438 317.435563 z M 261.306953 322.727125 C 261.628516 322.659312 262.031016 322.727125 262.181953 322.536812 C 262.304453 322.379313 262.216953 322.070875 262.216953 321.819313 C 262.223516 319.951188 262.722266 317.544938 261.586953 316.007125 C 261.223828 315.514937 260.451641 314.989937 259.679453 315.009625 C 258.434766 315.038063 257.868203 315.919625 257.308203 316.724625 C 257.295078 316.438063 257.253516 316.171187 257.150703 315.974312 C 256.912266 315.849625 256.459453 315.974312 256.240703 316.068375 C 256.056953 317.264937 256.146641 319.343062 256.091953 320.848063 C 256.076641 321.21775 255.851328 322.447125 256.179453 322.727125 C 256.404766 322.919625 257.076328 322.858375 257.211953 322.694313 C 257.349766 322.5215 257.286328 322.228375 257.308203 321.941813 C 257.395703 320.635875 257.382578 319.609938 257.868203 318.413375 C 258.170078 317.676188 258.926953 315.803688 260.116953 316.350563 C 261.114453 316.80775 261.191016 318.702125 261.088203 320.163375 C 261.020391 321.128062 260.760078 322.18025 261.306953 322.727125 z M 265.278086 322.768687 C 265.525273 322.679 265.750586 322.816813 265.975898 322.816813 C 266.577461 322.816813 267.179023 322.49525 267.581523 322.186812 C 267.931523 321.919938 268.334023 321.545875 268.484961 321.163063 C 268.697148 320.616188 268.655586 319.780562 268.504648 319.288375 C 268.408398 318.975563 268.012461 318.503062 267.658086 318.43525 C 267.472148 318.40025 267.095898 318.406813 266.850898 318.483375 C 266.358711 318.638688 265.100898 319.500563 265.100898 318.43525 C 265.100898 317.811812 265.647773 317.21025 266.126836 317.129313 C 266.509648 317.068062 266.986523 317.258375 267.179023 317.380875 C 267.336523 317.483687 267.356211 317.695875 267.555273 317.709 C 267.719336 317.724312 268.108711 317.396187 268.128398 317.203688 C 268.134961 317.107438 268.073711 316.943375 268.034336 316.882125 C 267.760898 316.459938 266.899023 316.171187 266.378398 316.103375 C 265.792148 316.022438 265.017773 316.575875 264.753086 316.93025 C 264.595586 317.142437 264.383398 317.396187 264.300273 317.634625 C 264.013711 318.483375 264.116523 319.249 264.676523 319.760875 C 265.531836 320.259625 266.522773 319.664625 267.301523 319.384625 C 267.651523 319.638375 267.745586 320.382125 267.555273 320.8415 C 267.507148 320.950875 267.314648 321.154313 267.227148 321.237437 C 267.069648 321.381813 266.741523 321.6465 266.454961 321.74275 C 266.111523 321.852125 265.409336 321.86525 265.175273 321.537125 C 264.971836 321.250563 264.991523 320.764937 264.724648 320.690562 C 264.534336 320.635875 264.306836 320.880875 264.074961 320.964 C 263.952461 321.784312 264.444648 322.193375 264.827461 322.5915 C 264.998086 322.624312 265.149023 322.685563 265.278086 322.768687 z M 271.759922 321.674937 C 271.116797 320.089 271.423047 317.991188 271.506172 316.164625 C 271.567422 314.845562 271.779609 313.506813 271.814609 312.27525 C 271.731484 312.124312 271.676797 311.947125 271.608984 311.789625 C 271.403359 311.702125 271.197734 311.605875 270.917734 311.584 C 270.618047 311.625563 270.001172 311.831187 269.994609 312.194313 C 269.988047 312.43275 270.138984 312.74775 270.351172 312.787125 C 270.548047 312.828688 270.624609 312.658062 270.788672 312.706187 C 270.747109 313.266188 270.650859 313.880875 270.611484 314.524 C 270.569922 315.132125 270.576484 315.77525 270.508672 316.3965 C 270.309609 318.1815 270.219922 319.6515 270.583047 321.163063 C 270.727422 321.755875 270.821484 322.366188 271.197734 322.646187 C 271.615547 322.952437 272.381172 322.685563 272.477422 322.234938 C 272.551797 321.874 272.101172 321.517437 271.759922 321.674937 z M 279.127422 317.162125 C 279.079297 317.0615 278.902109 317.100875 278.799297 317.05275 C 278.396797 316.514625 277.766797 316.068375 276.837109 316.096812 C 274.568672 316.158062 273.358984 318.68025 273.365547 320.880875 C 273.365547 321.257125 273.439922 321.755875 273.665234 322.077437 C 273.947422 322.475563 274.369609 322.685563 274.787422 322.816813 C 276.708047 322.823375 277.541484 321.749312 278.390234 320.690562 C 278.657109 321.62025 279.059609 323.029 280.085547 322.762125 C 280.439922 322.482125 280.365547 321.764625 279.921484 321.694625 C 279.558359 321.018687 279.306797 320.069313 279.236797 319.104625 C 279.197422 318.448375 279.352734 317.750563 279.127422 317.162125 z M 275.881172 317.435563 C 276.537422 317.019938 277.618047 317.074625 278.116797 317.573375 C 278.048984 317.9365 278.158359 318.428688 278.116797 318.748063 C 278.027109 319.452437 277.418984 320.327437 276.837109 320.90275 C 276.386484 321.353375 275.314609 322.09275 274.568672 321.530562 C 274.179297 320.089 274.813672 318.12025 275.881172 317.435563 z M 284.508125 314.928688 C 284.746562 313.915875 284.971875 312.706187 284.768438 311.728375 C 284.549688 311.584 284.221563 311.551187 284.08375 311.632125 C 283.379375 312.049937 283.495313 314.073375 283.202187 314.928688 C 282.504375 315.029313 281.754062 314.764625 281.24 315.029313 C 281.191875 315.30275 281.034375 315.788375 281.24 316.007125 C 281.657812 316.241188 282.327187 316.219313 282.970312 316.232438 C 282.941875 316.7115 282.8325 317.422438 282.80625 317.9365 C 282.723125 319.548687 282.716563 321.600563 283.626562 322.405562 C 284.260938 322.974312 285.499062 322.81025 286.3325 322.536812 C 286.6125 322.447125 286.940625 322.399 287.085 322.2765 C 287.371562 322.029313 287.18125 321.469313 286.98875 321.202437 C 286.339063 320.977125 285.260625 321.825875 284.604375 321.49775 C 284.20625 321.298687 284.151563 320.382125 284.112188 319.828688 C 284.029063 318.673687 284.166875 317.232125 284.27625 316.232438 C 285.09 316.1865 285.888438 316.3965 286.756875 316.267437 C 287.036875 316.042125 286.934062 315.427437 286.756875 315.125563 C 286.100625 314.968062 285.23875 315.009625 284.508125 314.928688 z M 291.405312 315.2415 C 290.762187 315.269937 290.08625 315.733687 289.729688 316.096812 C 289.594063 316.232438 289.471563 316.479625 289.3075 316.691813 C 288.854688 317.286812 288.425937 318.271187 288.316562 319.124312 C 288.130625 320.546187 288.65125 321.954937 289.443125 322.475563 C 289.594063 322.569625 289.957187 322.749 290.1825 322.781813 C 290.886875 322.884625 291.775 322.536812 292.280312 322.21525 C 292.901562 321.819313 293.538125 321.128062 293.811562 320.484938 C 294.316875 319.303688 294.098125 317.730875 293.58625 316.801188 C 293.415625 316.49275 293.161875 316.260875 292.901562 316.007125 C 292.464062 315.584938 292.026563 315.21525 291.405312 315.2415 z M 289.9025 317.737437 C 290.099375 317.374312 290.83875 316.37025 291.405312 316.350563 C 291.411875 316.350563 291.43375 316.309 291.46 316.322125 C 292.341563 316.704937 292.99125 317.676188 292.99125 319.043375 C 292.99125 319.809 292.573437 320.498063 292.109688 320.944313 C 291.698438 321.34025 290.865 321.784312 290.324687 321.6465 C 289.970312 321.559 289.729688 321.195875 289.61375 320.915875 C 289.24625 320.02775 289.449687 318.551188 289.9025 317.737437 z M 299.978125 316.827437 C 299.95625 316.978375 300.045937 317.019938 300.0875 317.107438 C 300.750312 317.56025 301.2775 317.068062 301.091563 316.376812 C 300.914375 316.103375 300.654063 315.913063 300.312812 315.794938 C 299.096563 315.385875 296.887187 315.768687 296.346875 316.575875 C 296.224375 316.383375 295.684062 316.350563 295.487188 316.49275 C 295.3625 316.582438 295.329687 316.882125 295.316563 317.135875 C 295.275 317.827125 295.37125 318.702125 295.316563 319.364937 C 295.21375 320.607438 295.21375 321.797438 295.342812 322.549937 C 295.465312 322.679 295.609687 322.781813 295.760625 322.884625 C 295.964062 322.8365 295.950938 322.843062 296.182812 322.858375 C 296.300938 322.762125 296.381875 322.630875 296.49125 322.5215 C 296.395 321.86525 296.484687 321.250563 296.545937 320.513375 C 296.642187 319.349625 296.635625 318.107125 297.127813 317.299937 C 297.668125 316.724625 298.945625 316.656813 299.978125 316.827437 z M 303.77125 322.768687 C 304.018438 322.679 304.24375 322.816813 304.469063 322.816813 C 305.070625 322.816813 305.672188 322.49525 306.074687 322.186812 C 306.424688 321.919938 306.827187 321.545875 306.978125 321.163063 C 307.190313 320.616188 307.14875 319.780562 306.997813 319.288375 C 306.901562 318.975563 306.505625 318.503062 306.15125 318.43525 C 305.965312 318.40025 305.589062 318.406813 305.344063 318.483375 C 304.851875 318.638688 303.594063 319.500563 303.594063 318.43525 C 303.594063 317.811812 304.140938 317.21025 304.62 317.129313 C 305.002813 317.068062 305.479687 317.258375 305.672188 317.380875 C 305.829687 317.483687 305.849375 317.695875 306.048437 317.709 C 306.2125 317.724312 306.601875 317.396187 306.621562 317.203688 C 306.628125 317.107438 306.566875 316.943375 306.5275 316.882125 C 306.254063 316.459938 305.392187 316.171187 304.871562 316.103375 C 304.285313 316.022438 303.510937 316.575875 303.24625 316.93025 C 303.08875 317.142437 302.876562 317.396187 302.793437 317.634625 C 302.506875 318.483375 302.609688 319.249 303.169688 319.760875 C 304.025 320.259625 305.015938 319.664625 305.794688 319.384625 C 306.144688 319.638375 306.23875 320.382125 306.048437 320.8415 C 306.000313 320.950875 305.807812 321.154313 305.720312 321.237437 C 305.562813 321.381813 305.234688 321.6465 304.948125 321.74275 C 304.604687 321.852125 303.9025 321.86525 303.668437 321.537125 C 303.465 321.250563 303.484688 320.764937 303.217812 320.690562 C 303.0275 320.635875 302.8 320.880875 302.568125 320.964 C 302.445625 321.784312 302.937813 322.193375 303.320625 322.5915 C 303.49125 322.624312 303.642187 322.685563 303.77125 322.768687 z " + style="stroke: #ffffff; stroke-width: 4" + id="path5" /> + <path + d="M 171.004219 322.974312 C 172.165781 322.974312 172.165781 320.854625 172.165781 320.143687 C 172.165781 319.15275 171.995156 318.168375 171.995156 317.162125 C 171.995156 316.013688 172.124219 314.86525 172.124219 313.703688 C 172.124219 313.581187 172.124219 313.095562 172.084844 312.631813 C 172.043281 312.200875 171.940469 311.708687 171.686719 311.708687 C 171.181406 311.708687 170.647656 311.885875 170.566719 312.487437 C 170.457344 313.34275 170.483594 314.279 170.483594 315.132125 L 170.498906 317.05275 C 170.512031 318.017437 170.737344 319.014937 170.737344 319.99275 C 170.737344 320.005875 170.737344 320.124 170.724219 320.218062 C 170.724219 320.314312 170.724219 320.410563 170.682656 320.410563 C 170.586406 320.410563 170.437656 320.060563 170.299844 319.71275 C 170.164219 319.349625 170.032969 318.966813 170.006719 318.885875 C 169.540781 317.599625 166.957344 312.568375 165.487344 312.568375 C 164.564219 312.568375 164.564219 314.559 164.564219 315.105875 C 164.564219 317.286812 164.673594 319.480875 164.673594 321.661812 C 164.673594 322.167125 165.139531 322.987437 165.725781 322.987437 C 166.382031 322.987437 166.436719 321.819313 166.436719 321.353375 C 166.436719 320.349312 166.287969 319.343062 166.287969 318.339 C 166.287969 317.389625 166.075781 316.444625 166.075781 315.482125 C 166.075781 315.466813 166.047344 315.208687 166.102031 315.208687 C 166.465156 315.208687 168.427344 319.391188 168.707344 320.034312 C 169.028906 320.8065 170.000156 322.974312 171.004219 322.974312 z M 174.988477 316.096812 C 174.367227 316.424937 174.209727 317.450875 174.058789 318.297438 C 173.691289 320.375563 173.697852 323.05525 176.261602 322.794938 C 177.230664 322.700875 178.256602 322.186812 178.845039 321.456187 C 179.144727 321.0865 179.433477 320.506813 179.520977 320.054 C 179.733164 318.966813 179.426914 317.881813 179.234414 317.05275 C 179.166602 316.766188 179.118477 316.4665 178.871289 316.383375 C 178.652539 316.309 178.236914 316.444625 178.147227 316.61525 C 178.005039 316.888688 178.324414 317.5865 178.407539 317.96275 C 178.510352 318.448375 178.571602 319.104625 178.536602 319.6165 C 178.455664 320.74525 177.410039 321.661812 176.261602 321.764625 C 175.988164 321.790875 175.625039 321.810563 175.406289 321.709938 C 175.132852 321.578688 174.997227 321.108375 174.942539 320.751812 C 174.675664 318.934 175.338477 317.846812 175.480664 316.357125 C 175.371289 316.21275 175.152539 316.17775 174.988477 316.096812 z M 186.200781 322.399 C 186.467656 321.749312 186.555156 320.764937 186.686406 319.83525 C 186.808906 318.947125 186.924844 317.969313 187.342656 317.444313 C 187.513281 317.232125 187.944219 316.904 188.278906 316.93025 C 188.838906 316.971812 189.234844 317.763688 189.221719 318.413375 C 189.215156 318.721812 189.051094 319.207438 188.906719 319.609938 C 188.703281 320.191813 188.462656 320.896187 188.510781 321.626812 C 188.539219 322.003062 188.729531 322.61775 189.051094 322.794938 C 189.385781 322.980875 189.864844 322.685563 189.932656 322.37275 C 189.993906 322.09275 189.652656 321.893687 189.617656 321.572125 C 189.597969 321.408062 189.639531 321.14775 189.672344 320.977125 C 189.823281 320.191813 190.295781 319.268687 190.357031 318.4965 C 190.411719 317.853375 190.157969 317.177437 189.851719 316.733375 C 189.420781 316.1165 188.639844 315.598062 187.710156 315.878062 C 187.130469 316.05525 186.767344 316.418375 186.342969 316.958687 C 186.310156 316.68525 186.097969 316.376812 185.914219 316.158062 C 185.120156 315.61775 183.794531 316.035563 183.241094 316.704937 C 183.061719 316.917125 183.007031 317.170875 182.810156 317.299937 C 182.823281 316.998063 182.816719 316.05525 182.530156 315.904313 C 182.331094 315.803688 182.022656 315.994 181.757969 316.022438 C 181.523906 316.389937 181.668281 316.875563 181.703281 317.389625 C 181.784219 318.52275 181.893594 319.979625 181.812656 321.06025 C 181.777656 321.482438 181.539219 321.919938 181.585156 322.256813 C 181.613594 322.466813 181.845469 322.630875 181.928594 322.768687 C 182.398906 322.93275 182.672344 322.685563 182.871406 322.256813 C 182.952344 320.5265 183.308906 318.831187 184.032969 317.499 C 184.341406 317.28025 184.586406 317.013375 185.148594 317.046187 C 185.640781 318.255875 184.975781 320.375563 185.148594 321.858687 C 185.181406 322.18025 185.380469 322.37275 185.516094 322.514937 C 185.782969 322.5215 185.995156 322.453688 186.200781 322.399 z M 192.483555 317.334938 C 192.49668 316.534312 192.55793 315.173687 192.483555 314.224312 C 192.455117 313.889625 192.40043 313.137125 192.100742 313.075875 C 191.92793 313.040875 191.763867 313.178688 191.615117 313.178688 C 191.28043 314.018687 191.62168 315.420875 191.512305 316.77275 C 191.435742 317.689312 191.36793 318.654 191.409492 319.55525 C 191.457617 320.568062 191.483867 322.105875 192.249492 321.90025 C 192.448555 321.845562 192.61918 321.810563 192.686992 321.62025 C 193.645117 322.193375 195.272617 322.18025 196.106055 321.491188 C 196.33793 321.298687 196.447305 321.053688 196.666055 320.880875 C 196.974492 320.191813 197.46668 319.200875 197.27418 318.249312 C 197.18668 317.80525 196.95918 317.422438 196.788555 317.05275 C 196.270117 316.499312 195.791055 316.048687 194.826367 316.035563 C 193.719492 316.022438 192.966992 316.704937 192.483555 317.334938 z M 194.34293 321.06025 C 193.699805 321.066813 193.17918 320.799937 192.763555 320.471812 C 192.74168 318.796187 193.207617 317.464 194.417305 317.081187 C 194.732305 316.978375 195.327305 317.100875 195.546055 317.232125 C 196.701055 317.9365 196.318242 320.178688 195.285742 320.826188 C 195.12168 320.929 194.58793 321.06025 194.34293 321.06025 z M 199.577617 319.522438 C 200.24918 319.631813 201.041055 319.535563 201.957617 319.459 C 202.955117 319.378062 203.816992 319.522438 204.21293 318.947125 C 204.547617 317.921187 204.261055 316.698375 203.49543 316.1165 C 202.941992 315.694313 201.935742 315.412125 201.170117 315.604625 C 200.658242 315.733687 199.831367 316.274 199.393867 316.814312 C 198.608555 317.779 197.998242 319.67775 198.615117 320.964 C 198.96293 321.517437 199.27793 321.983375 199.844492 322.289625 C 200.822305 322.823375 201.951055 322.563063 202.858867 322.263375 C 203.289805 322.119 203.77543 321.954937 204.061992 321.723063 C 204.241367 321.578688 204.425117 321.292125 204.363867 321.0865 C 204.315742 320.909312 203.904492 320.539625 203.646367 320.546187 C 203.421055 320.55275 203.24168 320.8415 203.009805 320.964 C 202.395117 321.298687 201.27293 321.668375 200.481055 321.333687 C 199.83793 321.06025 199.551367 320.355875 199.577617 319.522438 z M 202.55918 316.93025 C 202.86543 317.094313 203.235117 317.599625 203.160742 318.229625 C 201.99918 318.24275 200.96668 318.345562 199.818242 318.43525 C 200.172617 317.553688 201.294805 316.260875 202.55918 316.93025 z M 210.160742 316.827437 C 210.138867 316.978375 210.228555 317.019938 210.270117 317.107438 C 210.93293 317.56025 211.460117 317.068062 211.27418 316.376812 C 211.096992 316.103375 210.83668 315.913063 210.49543 315.794938 C 209.27918 315.385875 207.069805 315.768687 206.529492 316.575875 C 206.406992 316.383375 205.86668 316.350563 205.669805 316.49275 C 205.545117 316.582438 205.512305 316.882125 205.49918 317.135875 C 205.457617 317.827125 205.553867 318.702125 205.49918 319.364937 C 205.396367 320.607438 205.396367 321.797438 205.52543 322.549937 C 205.64793 322.679 205.792305 322.781813 205.943242 322.884625 C 206.14668 322.8365 206.133555 322.843062 206.36543 322.858375 C 206.483555 322.762125 206.564492 322.630875 206.673867 322.5215 C 206.577617 321.86525 206.667305 321.250563 206.728555 320.513375 C 206.824805 319.349625 206.818242 318.107125 207.31043 317.299937 C 207.850742 316.724625 209.128242 316.656813 210.160742 316.827437 z M 219.08793 315.2415 C 218.444805 315.269937 217.768867 315.733687 217.412305 316.096812 C 217.27668 316.232438 217.15418 316.479625 216.990117 316.691813 C 216.537305 317.286812 216.108555 318.271187 215.99918 319.124312 C 215.813242 320.546187 216.333867 321.954937 217.125742 322.475563 C 217.27668 322.569625 217.639805 322.749 217.865117 322.781813 C 218.569492 322.884625 219.457617 322.536812 219.96293 322.21525 C 220.58418 321.819313 221.220742 321.128062 221.49418 320.484938 C 221.999492 319.303688 221.780742 317.730875 221.268867 316.801188 C 221.098242 316.49275 220.844492 316.260875 220.58418 316.007125 C 220.14668 315.584938 219.70918 315.21525 219.08793 315.2415 z M 217.585117 317.737437 C 217.781992 317.374312 218.521367 316.37025 219.08793 316.350563 C 219.094492 316.350563 219.116367 316.309 219.142617 316.322125 C 220.02418 316.704937 220.673867 317.676188 220.673867 319.043375 C 220.673867 319.809 220.256055 320.498063 219.792305 320.944313 C 219.381055 321.34025 218.547617 321.784312 218.007305 321.6465 C 217.65293 321.559 217.412305 321.195875 217.296367 320.915875 C 216.928867 320.02775 217.132305 318.551188 217.585117 317.737437 z M 226.116367 312.8965 C 226.538555 313.082437 226.99793 313.334 227.483555 313.581187 C 227.912305 313.799937 228.522617 314.237437 228.883555 314.163063 C 229.178867 314.099625 229.533242 313.404 229.436992 313.191812 C 229.288242 312.87025 228.365117 312.644937 227.975742 312.439312 C 227.345742 312.111187 226.888555 311.796187 226.409492 311.59275 C 225.96543 311.55775 225.534492 311.647438 225.206367 311.885875 C 224.43418 312.828688 224.33793 314.237437 224.228555 315.727125 C 223.292305 315.646187 222.636055 315.823375 222.92918 316.834 C 223.169805 317.107438 223.83918 316.936812 224.228555 317.0615 C 224.167305 318.345562 224.427617 319.343062 224.427617 320.539625 C 224.427617 321.388375 224.228555 322.289625 224.65293 322.788375 C 224.913242 322.788375 225.18668 322.803688 225.40543 322.755562 C 225.521367 322.5915 225.637305 322.392437 225.663555 322.202125 C 225.910742 320.629313 225.425117 318.693375 225.569492 317.129313 C 226.18418 317.013375 227.091992 317.081187 227.448555 316.669938 C 227.74168 316.33525 227.544805 315.891188 227.256055 315.694313 C 226.86668 315.420875 226.696055 315.61775 226.348242 315.727125 C 226.094492 315.81025 225.84293 315.794938 225.534492 315.858375 C 225.541055 315.324625 225.602305 314.784312 225.691992 314.263688 C 225.779492 313.758375 225.74668 313.178688 226.116367 312.8965 z M 237.258125 314.928688 C 237.496562 313.915875 237.721875 312.706187 237.518438 311.728375 C 237.299688 311.584 236.971563 311.551187 236.83375 311.632125 C 236.129375 312.049937 236.245312 314.073375 235.952187 314.928688 C 235.254375 315.029313 234.504062 314.764625 233.99 315.029313 C 233.941875 315.30275 233.784375 315.788375 233.99 316.007125 C 234.407812 316.241188 235.077187 316.219313 235.720312 316.232438 C 235.691875 316.7115 235.5825 317.422438 235.55625 317.9365 C 235.473125 319.548687 235.466562 321.600563 236.376562 322.405562 C 237.010937 322.974312 238.249062 322.81025 239.0825 322.536812 C 239.3625 322.447125 239.690625 322.399 239.835 322.2765 C 240.121562 322.029313 239.93125 321.469313 239.73875 321.202437 C 239.089062 320.977125 238.010625 321.825875 237.354375 321.49775 C 236.95625 321.298687 236.901562 320.382125 236.862188 319.828688 C 236.779062 318.673687 236.916875 317.232125 237.02625 316.232438 C 237.84 316.1865 238.638437 316.3965 239.506875 316.267437 C 239.786875 316.042125 239.684062 315.427437 239.506875 315.125563 C 238.850625 314.968062 237.98875 315.009625 237.258125 314.928688 z M 245.728125 316.827437 C 245.70625 316.978375 245.795937 317.019938 245.8375 317.107438 C 246.500313 317.56025 247.0275 317.068062 246.841562 316.376812 C 246.664375 316.103375 246.404062 315.913063 246.062813 315.794938 C 244.846563 315.385875 242.637187 315.768687 242.096875 316.575875 C 241.974375 316.383375 241.434062 316.350563 241.237188 316.49275 C 241.1125 316.582438 241.079687 316.882125 241.066562 317.135875 C 241.025 317.827125 241.12125 318.702125 241.066562 319.364937 C 240.96375 320.607438 240.96375 321.797438 241.092812 322.549937 C 241.215312 322.679 241.359688 322.781813 241.510625 322.884625 C 241.714062 322.8365 241.700937 322.843062 241.932812 322.858375 C 242.050937 322.762125 242.131875 322.630875 242.24125 322.5215 C 242.145 321.86525 242.234688 321.250563 242.295937 320.513375 C 242.392187 319.349625 242.385625 318.107125 242.877813 317.299937 C 243.418125 316.724625 244.695625 316.656813 245.728125 316.827437 z M 253.574687 317.162125 C 253.526562 317.0615 253.349375 317.100875 253.246562 317.05275 C 252.844063 316.514625 252.214062 316.068375 251.284375 316.096812 C 249.015938 316.158062 247.80625 318.68025 247.812813 320.880875 C 247.812813 321.257125 247.887187 321.755875 248.1125 322.077437 C 248.394687 322.475563 248.816875 322.685563 249.234688 322.816813 C 251.155312 322.823375 251.98875 321.749312 252.8375 320.690562 C 253.104375 321.62025 253.506875 323.029 254.532812 322.762125 C 254.887187 322.482125 254.812813 321.764625 254.36875 321.694625 C 254.005625 321.018687 253.754062 320.069313 253.684062 319.104625 C 253.644687 318.448375 253.8 317.750563 253.574687 317.162125 z M 250.328438 317.435563 C 250.984688 317.019938 252.065313 317.074625 252.564062 317.573375 C 252.49625 317.9365 252.605625 318.428688 252.564062 318.748063 C 252.474375 319.452437 251.86625 320.327437 251.284375 320.90275 C 250.83375 321.353375 249.761875 322.09275 249.015938 321.530562 C 248.626562 320.089 249.260937 318.12025 250.328438 317.435563 z M 261.306953 322.727125 C 261.628516 322.659312 262.031016 322.727125 262.181953 322.536812 C 262.304453 322.379313 262.216953 322.070875 262.216953 321.819313 C 262.223516 319.951188 262.722266 317.544938 261.586953 316.007125 C 261.223828 315.514937 260.451641 314.989937 259.679453 315.009625 C 258.434766 315.038063 257.868203 315.919625 257.308203 316.724625 C 257.295078 316.438063 257.253516 316.171187 257.150703 315.974312 C 256.912266 315.849625 256.459453 315.974312 256.240703 316.068375 C 256.056953 317.264937 256.146641 319.343062 256.091953 320.848063 C 256.076641 321.21775 255.851328 322.447125 256.179453 322.727125 C 256.404766 322.919625 257.076328 322.858375 257.211953 322.694313 C 257.349766 322.5215 257.286328 322.228375 257.308203 321.941813 C 257.395703 320.635875 257.382578 319.609938 257.868203 318.413375 C 258.170078 317.676188 258.926953 315.803688 260.116953 316.350563 C 261.114453 316.80775 261.191016 318.702125 261.088203 320.163375 C 261.020391 321.128062 260.760078 322.18025 261.306953 322.727125 z M 265.278086 322.768687 C 265.525273 322.679 265.750586 322.816813 265.975898 322.816813 C 266.577461 322.816813 267.179023 322.49525 267.581523 322.186812 C 267.931523 321.919938 268.334023 321.545875 268.484961 321.163063 C 268.697148 320.616188 268.655586 319.780562 268.504648 319.288375 C 268.408398 318.975563 268.012461 318.503062 267.658086 318.43525 C 267.472148 318.40025 267.095898 318.406813 266.850898 318.483375 C 266.358711 318.638688 265.100898 319.500563 265.100898 318.43525 C 265.100898 317.811812 265.647773 317.21025 266.126836 317.129313 C 266.509648 317.068062 266.986523 317.258375 267.179023 317.380875 C 267.336523 317.483687 267.356211 317.695875 267.555273 317.709 C 267.719336 317.724312 268.108711 317.396187 268.128398 317.203688 C 268.134961 317.107438 268.073711 316.943375 268.034336 316.882125 C 267.760898 316.459938 266.899023 316.171187 266.378398 316.103375 C 265.792148 316.022438 265.017773 316.575875 264.753086 316.93025 C 264.595586 317.142437 264.383398 317.396187 264.300273 317.634625 C 264.013711 318.483375 264.116523 319.249 264.676523 319.760875 C 265.531836 320.259625 266.522773 319.664625 267.301523 319.384625 C 267.651523 319.638375 267.745586 320.382125 267.555273 320.8415 C 267.507148 320.950875 267.314648 321.154313 267.227148 321.237437 C 267.069648 321.381813 266.741523 321.6465 266.454961 321.74275 C 266.111523 321.852125 265.409336 321.86525 265.175273 321.537125 C 264.971836 321.250563 264.991523 320.764937 264.724648 320.690562 C 264.534336 320.635875 264.306836 320.880875 264.074961 320.964 C 263.952461 321.784312 264.444648 322.193375 264.827461 322.5915 C 264.998086 322.624312 265.149023 322.685563 265.278086 322.768687 z M 271.759922 321.674937 C 271.116797 320.089 271.423047 317.991188 271.506172 316.164625 C 271.567422 314.845562 271.779609 313.506813 271.814609 312.27525 C 271.731484 312.124312 271.676797 311.947125 271.608984 311.789625 C 271.403359 311.702125 271.197734 311.605875 270.917734 311.584 C 270.618047 311.625563 270.001172 311.831187 269.994609 312.194313 C 269.988047 312.43275 270.138984 312.74775 270.351172 312.787125 C 270.548047 312.828688 270.624609 312.658062 270.788672 312.706187 C 270.747109 313.266188 270.650859 313.880875 270.611484 314.524 C 270.569922 315.132125 270.576484 315.77525 270.508672 316.3965 C 270.309609 318.1815 270.219922 319.6515 270.583047 321.163063 C 270.727422 321.755875 270.821484 322.366188 271.197734 322.646187 C 271.615547 322.952437 272.381172 322.685563 272.477422 322.234938 C 272.551797 321.874 272.101172 321.517437 271.759922 321.674937 z M 279.127422 317.162125 C 279.079297 317.0615 278.902109 317.100875 278.799297 317.05275 C 278.396797 316.514625 277.766797 316.068375 276.837109 316.096812 C 274.568672 316.158062 273.358984 318.68025 273.365547 320.880875 C 273.365547 321.257125 273.439922 321.755875 273.665234 322.077437 C 273.947422 322.475563 274.369609 322.685563 274.787422 322.816813 C 276.708047 322.823375 277.541484 321.749312 278.390234 320.690562 C 278.657109 321.62025 279.059609 323.029 280.085547 322.762125 C 280.439922 322.482125 280.365547 321.764625 279.921484 321.694625 C 279.558359 321.018687 279.306797 320.069313 279.236797 319.104625 C 279.197422 318.448375 279.352734 317.750563 279.127422 317.162125 z M 275.881172 317.435563 C 276.537422 317.019938 277.618047 317.074625 278.116797 317.573375 C 278.048984 317.9365 278.158359 318.428688 278.116797 318.748063 C 278.027109 319.452437 277.418984 320.327437 276.837109 320.90275 C 276.386484 321.353375 275.314609 322.09275 274.568672 321.530562 C 274.179297 320.089 274.813672 318.12025 275.881172 317.435563 z M 284.508125 314.928688 C 284.746562 313.915875 284.971875 312.706187 284.768438 311.728375 C 284.549688 311.584 284.221563 311.551187 284.08375 311.632125 C 283.379375 312.049937 283.495313 314.073375 283.202187 314.928688 C 282.504375 315.029313 281.754062 314.764625 281.24 315.029313 C 281.191875 315.30275 281.034375 315.788375 281.24 316.007125 C 281.657812 316.241188 282.327187 316.219313 282.970312 316.232438 C 282.941875 316.7115 282.8325 317.422438 282.80625 317.9365 C 282.723125 319.548687 282.716563 321.600563 283.626562 322.405562 C 284.260938 322.974312 285.499062 322.81025 286.3325 322.536812 C 286.6125 322.447125 286.940625 322.399 287.085 322.2765 C 287.371562 322.029313 287.18125 321.469313 286.98875 321.202437 C 286.339063 320.977125 285.260625 321.825875 284.604375 321.49775 C 284.20625 321.298687 284.151563 320.382125 284.112188 319.828688 C 284.029063 318.673687 284.166875 317.232125 284.27625 316.232438 C 285.09 316.1865 285.888438 316.3965 286.756875 316.267437 C 287.036875 316.042125 286.934062 315.427437 286.756875 315.125563 C 286.100625 314.968062 285.23875 315.009625 284.508125 314.928688 z M 291.405312 315.2415 C 290.762187 315.269937 290.08625 315.733687 289.729688 316.096812 C 289.594063 316.232438 289.471563 316.479625 289.3075 316.691813 C 288.854688 317.286812 288.425937 318.271187 288.316562 319.124312 C 288.130625 320.546187 288.65125 321.954937 289.443125 322.475563 C 289.594063 322.569625 289.957187 322.749 290.1825 322.781813 C 290.886875 322.884625 291.775 322.536812 292.280312 322.21525 C 292.901562 321.819313 293.538125 321.128062 293.811562 320.484938 C 294.316875 319.303688 294.098125 317.730875 293.58625 316.801188 C 293.415625 316.49275 293.161875 316.260875 292.901562 316.007125 C 292.464062 315.584938 292.026563 315.21525 291.405312 315.2415 z M 289.9025 317.737437 C 290.099375 317.374312 290.83875 316.37025 291.405312 316.350563 C 291.411875 316.350563 291.43375 316.309 291.46 316.322125 C 292.341563 316.704937 292.99125 317.676188 292.99125 319.043375 C 292.99125 319.809 292.573437 320.498063 292.109688 320.944313 C 291.698438 321.34025 290.865 321.784312 290.324687 321.6465 C 289.970312 321.559 289.729688 321.195875 289.61375 320.915875 C 289.24625 320.02775 289.449687 318.551188 289.9025 317.737437 z M 299.978125 316.827437 C 299.95625 316.978375 300.045937 317.019938 300.0875 317.107438 C 300.750312 317.56025 301.2775 317.068062 301.091563 316.376812 C 300.914375 316.103375 300.654063 315.913063 300.312812 315.794938 C 299.096563 315.385875 296.887187 315.768687 296.346875 316.575875 C 296.224375 316.383375 295.684062 316.350563 295.487188 316.49275 C 295.3625 316.582438 295.329687 316.882125 295.316563 317.135875 C 295.275 317.827125 295.37125 318.702125 295.316563 319.364937 C 295.21375 320.607438 295.21375 321.797438 295.342812 322.549937 C 295.465312 322.679 295.609687 322.781813 295.760625 322.884625 C 295.964062 322.8365 295.950938 322.843062 296.182812 322.858375 C 296.300938 322.762125 296.381875 322.630875 296.49125 322.5215 C 296.395 321.86525 296.484687 321.250563 296.545937 320.513375 C 296.642187 319.349625 296.635625 318.107125 297.127813 317.299937 C 297.668125 316.724625 298.945625 316.656813 299.978125 316.827437 z M 303.77125 322.768687 C 304.018438 322.679 304.24375 322.816813 304.469063 322.816813 C 305.070625 322.816813 305.672188 322.49525 306.074687 322.186812 C 306.424688 321.919938 306.827187 321.545875 306.978125 321.163063 C 307.190313 320.616188 307.14875 319.780562 306.997813 319.288375 C 306.901562 318.975563 306.505625 318.503062 306.15125 318.43525 C 305.965312 318.40025 305.589062 318.406813 305.344063 318.483375 C 304.851875 318.638688 303.594063 319.500563 303.594063 318.43525 C 303.594063 317.811812 304.140938 317.21025 304.62 317.129313 C 305.002813 317.068062 305.479687 317.258375 305.672188 317.380875 C 305.829687 317.483687 305.849375 317.695875 306.048437 317.709 C 306.2125 317.724312 306.601875 317.396187 306.621562 317.203688 C 306.628125 317.107438 306.566875 316.943375 306.5275 316.882125 C 306.254063 316.459938 305.392187 316.171187 304.871562 316.103375 C 304.285313 316.022438 303.510937 316.575875 303.24625 316.93025 C 303.08875 317.142437 302.876562 317.396187 302.793437 317.634625 C 302.506875 318.483375 302.609688 319.249 303.169688 319.760875 C 304.025 320.259625 305.015938 319.664625 305.794688 319.384625 C 306.144688 319.638375 306.23875 320.382125 306.048437 320.8415 C 306.000313 320.950875 305.807812 321.154313 305.720312 321.237437 C 305.562813 321.381813 305.234688 321.6465 304.948125 321.74275 C 304.604687 321.852125 303.9025 321.86525 303.668437 321.537125 C 303.465 321.250563 303.484688 320.764937 303.217812 320.690562 C 303.0275 320.635875 302.8 320.880875 302.568125 320.964 C 302.445625 321.784312 302.937813 322.193375 303.320625 322.5915 C 303.49125 322.624312 303.642187 322.685563 303.77125 322.768687 z " + id="path6" /> + </g> + </g> + <g + id="matplotlib.axis_2"> + <g + id="text_2"> + <path + d="M 40.645625 230.911906 C 40.523125 230.323469 40.262812 229.811594 39.621875 229.811594 C 39.114375 229.811594 38.937188 230.638469 38.937188 230.986281 C 38.937188 231.082531 38.950312 231.172219 38.965625 231.253156 C 39.020312 231.561594 39.053125 232.108469 39.081562 232.749406 C 39.107812 233.405656 39.120937 234.164719 39.149375 234.890969 C 39.204062 236.358781 39.313437 237.774094 39.635 238.082531 C 39.805625 238.253156 40.09875 238.513469 40.37875 238.513469 C 40.88625 238.513469 40.899375 237.535656 40.899375 237.214094 C 40.899375 236.531594 40.770312 235.853469 40.770312 235.184094 C 40.770312 235.155656 40.770312 235.087844 40.783437 235.074719 C 40.879687 234.965344 43.277187 234.917219 43.627187 234.917219 C 45.000937 234.917219 46.368125 235.013469 47.755 235.013469 L 48.44625 235.013469 C 48.72625 235.000344 49.034687 234.971906 49.314687 234.917219 C 49.887813 234.820969 50.38875 234.582531 50.38875 234.035656 C 50.38875 233.460344 49.588125 233.405656 49.183437 233.392531 L 48.739375 233.392531 C 47.496875 233.392531 46.245625 233.591594 44.987812 233.591594 L 44.78875 233.591594 C 44.399375 233.591594 44.016562 233.530344 43.627187 233.530344 C 43.386562 233.530344 42.771875 233.530344 42.183437 233.515031 C 41.581875 233.501906 41.015313 233.475656 40.857812 233.392531 C 40.79 233.366281 40.755 233.228469 40.72875 233.044719 C 40.715625 232.874094 40.72875 232.688156 40.72875 232.620344 C 40.72875 232.408156 40.741875 232.147844 40.72875 231.841594 C 40.72875 231.546281 40.700312 231.218156 40.645625 230.911906 z M 44.200313 224.423781 C 44.35125 224.445656 44.392812 224.355969 44.480312 224.314406 C 44.933125 223.651594 44.440937 223.124406 43.749688 223.310344 C 43.47625 223.487531 43.285938 223.747844 43.167812 224.089094 C 42.75875 225.305344 43.141562 227.514719 43.94875 228.055031 C 43.75625 228.177531 43.723438 228.717844 43.865625 228.914719 C 43.955312 229.039406 44.255 229.072219 44.50875 229.085344 C 45.2 229.126906 46.075 229.030656 46.737812 229.085344 C 47.980312 229.188156 49.170313 229.188156 49.922812 229.059094 C 50.051875 228.936594 50.154688 228.792219 50.2575 228.641281 C 50.209375 228.437844 50.215938 228.450969 50.23125 228.219094 C 50.135 228.100969 50.00375 228.020031 49.894375 227.910656 C 49.238125 228.006906 48.623438 227.917219 47.88625 227.855969 C 46.7225 227.759719 45.48 227.766281 44.672812 227.274094 C 44.0975 226.733781 44.029688 225.456281 44.200313 224.423781 z M 44.535 216.577219 C 44.434375 216.625344 44.47375 216.802531 44.425625 216.905344 C 43.8875 217.307844 43.44125 217.937844 43.469687 218.867531 C 43.530938 221.135969 46.053125 222.345656 48.25375 222.339094 C 48.63 222.339094 49.12875 222.264719 49.450313 222.039406 C 49.848438 221.757219 50.058438 221.335031 50.189687 220.917219 C 50.19625 218.996594 49.122188 218.163156 48.063437 217.314406 C 48.993125 217.047531 50.401875 216.645031 50.135 215.619094 C 49.855 215.264719 49.1375 215.339094 49.0675 215.783156 C 48.391562 216.146281 47.442188 216.397844 46.4775 216.467844 C 45.82125 216.507219 45.123438 216.351906 44.535 216.577219 z M 44.808437 219.823469 C 44.392812 219.167219 44.4475 218.086594 44.94625 217.587844 C 45.309375 217.655656 45.801563 217.546281 46.120937 217.587844 C 46.825313 217.677531 47.700313 218.285656 48.275625 218.867531 C 48.72625 219.318156 49.465625 220.390031 48.903438 221.135969 C 47.461875 221.525344 45.493125 220.890969 44.808437 219.823469 z M 50.1 208.844953 C 50.032187 208.523391 50.1 208.120891 49.909688 207.969953 C 49.752187 207.847453 49.44375 207.934953 49.192188 207.934953 C 47.324063 207.928391 44.917812 207.429641 43.38 208.564953 C 42.887813 208.928078 42.362813 209.700266 42.3825 210.472453 C 42.410938 211.717141 43.2925 212.283703 44.0975 212.843703 C 43.810938 212.856828 43.544063 212.898391 43.347188 213.001203 C 43.2225 213.239641 43.347188 213.692453 43.44125 213.911203 C 44.637813 214.094953 46.715938 214.005266 48.220937 214.059953 C 48.590625 214.075266 49.82 214.300578 50.1 213.972453 C 50.2925 213.747141 50.23125 213.075578 50.067188 212.939953 C 49.894375 212.802141 49.60125 212.865578 49.314687 212.843703 C 48.00875 212.756203 46.982813 212.769328 45.78625 212.283703 C 45.049062 211.981828 43.176563 211.224953 43.723438 210.034953 C 44.180625 209.037453 46.075 208.960891 47.53625 209.063703 C 48.500937 209.131516 49.553125 209.391828 50.1 208.844953 z M 50.141562 204.87382 C 50.051875 204.626633 50.189687 204.40132 50.189687 204.176008 C 50.189687 203.574445 49.868125 202.972883 49.559688 202.570383 C 49.292813 202.220383 48.91875 201.817883 48.535938 201.666945 C 47.989063 201.454758 47.153438 201.49632 46.66125 201.647258 C 46.348438 201.743508 45.875937 202.139445 45.808125 202.49382 C 45.773125 202.679758 45.779688 203.056008 45.85625 203.301008 C 46.011562 203.793195 46.873438 205.051008 45.808125 205.051008 C 45.184688 205.051008 44.583125 204.504133 44.502187 204.02507 C 44.440938 203.642258 44.63125 203.165383 44.75375 202.972883 C 44.856563 202.815383 45.06875 202.795695 45.081875 202.596633 C 45.097188 202.43257 44.769063 202.043195 44.576563 202.023508 C 44.480313 202.016945 44.31625 202.078195 44.255 202.11757 C 43.832813 202.391008 43.544063 203.252883 43.47625 203.773508 C 43.395313 204.359758 43.94875 205.134133 44.303125 205.39882 C 44.515313 205.55632 44.769063 205.768508 45.0075 205.851633 C 45.85625 206.138195 46.621875 206.035383 47.13375 205.475383 C 47.6325 204.62007 47.0375 203.629133 46.7575 202.850383 C 47.01125 202.500383 47.755 202.40632 48.214375 202.596633 C 48.32375 202.644758 48.527188 202.837258 48.610312 202.924758 C 48.754688 203.082258 49.019375 203.410383 49.115625 203.696945 C 49.225 204.040383 49.238125 204.74257 48.91 204.976633 C 48.623438 205.18007 48.137813 205.160383 48.063437 205.427258 C 48.00875 205.61757 48.25375 205.84507 48.336875 206.076945 C 49.157187 206.199445 49.56625 205.707258 49.964375 205.324445 C 49.997188 205.15382 50.058438 205.002883 50.141562 204.87382 z M 49.047812 198.391984 C 47.461875 199.035109 45.364063 198.728859 43.5375 198.645734 C 42.218438 198.584484 40.879688 198.372297 39.648125 198.337297 C 39.497188 198.420422 39.32 198.475109 39.1625 198.542922 C 39.075 198.748547 38.97875 198.954172 38.956875 199.234172 C 38.998438 199.533859 39.204062 200.150734 39.567188 200.157297 C 39.805625 200.163859 40.120625 200.012922 40.16 199.800734 C 40.201563 199.603859 40.030938 199.527297 40.079062 199.363234 C 40.639063 199.404797 41.25375 199.501047 41.896875 199.540422 C 42.505 199.581984 43.148125 199.575422 43.769375 199.643234 C 45.554375 199.842297 47.024375 199.931984 48.535938 199.568859 C 49.12875 199.424484 49.739063 199.330422 50.019063 198.954172 C 50.325313 198.536359 50.058438 197.770734 49.607813 197.674484 C 49.246875 197.600109 48.890313 198.050734 49.047812 198.391984 z M 44.535 191.024484 C 44.434375 191.072609 44.47375 191.249797 44.425625 191.352609 C 43.8875 191.755109 43.44125 192.385109 43.469687 193.314797 C 43.530938 195.583234 46.053125 196.792922 48.25375 196.786359 C 48.63 196.786359 49.12875 196.711984 49.450313 196.486672 C 49.848438 196.204484 50.058438 195.782297 50.189688 195.364484 C 50.19625 193.443859 49.122188 192.610422 48.063437 191.761672 C 48.993125 191.494797 50.401875 191.092297 50.135 190.066359 C 49.855 189.711984 49.1375 189.786359 49.0675 190.230422 C 48.391562 190.593547 47.442188 190.845109 46.4775 190.915109 C 45.82125 190.954484 45.123438 190.799172 44.535 191.024484 z M 44.808438 194.270734 C 44.392813 193.614484 44.4475 192.533859 44.94625 192.035109 C 45.309375 192.102922 45.801563 191.993547 46.120938 192.035109 C 46.825313 192.124797 47.700313 192.732922 48.275625 193.314797 C 48.72625 193.765422 49.465625 194.837297 48.903438 195.583234 C 47.461875 195.972609 45.493125 195.338234 44.808438 194.270734 z M 42.301563 185.643781 C 41.28875 185.405344 40.079062 185.180031 39.10125 185.383469 C 38.956875 185.602219 38.924063 185.930344 39.005 186.068156 C 39.422812 186.772531 41.44625 186.656594 42.301563 186.949719 C 42.402188 187.647531 42.1375 188.397844 42.402188 188.911906 C 42.675625 188.960031 43.16125 189.117531 43.38 188.911906 C 43.614063 188.494094 43.592188 187.824719 43.605313 187.181594 C 44.084375 187.210031 44.795313 187.319406 45.309375 187.345656 C 46.921563 187.428781 48.973438 187.435344 49.778438 186.525344 C 50.347188 185.890969 50.183125 184.652844 49.909688 183.819406 C 49.82 183.539406 49.771875 183.211281 49.649375 183.066906 C 49.402188 182.780344 48.842188 182.970656 48.575313 183.163156 C 48.35 183.812844 49.19875 184.891281 48.870625 185.547531 C 48.671563 185.945656 47.755 186.000344 47.201563 186.039719 C 46.046563 186.122844 44.605 185.985031 43.605313 185.875656 C 43.559375 185.061906 43.769375 184.263469 43.640313 183.395031 C 43.415 183.115031 42.800313 183.217844 42.498438 183.395031 C 42.340938 184.051281 42.3825 184.913156 42.301563 185.643781 z M 42.614375 178.746594 C 42.642813 179.389719 43.106563 180.065656 43.469687 180.422219 C 43.605313 180.557844 43.8525 180.680344 44.064688 180.844406 C 44.659688 181.297219 45.644063 181.725969 46.497188 181.835344 C 47.919063 182.021281 49.327813 181.500656 49.848438 180.708781 C 49.9425 180.557844 50.121875 180.194719 50.154688 179.969406 C 50.2575 179.265031 49.909688 178.376906 49.588125 177.871594 C 49.192188 177.250344 48.500938 176.613781 47.857813 176.340344 C 46.676563 175.835031 45.10375 176.053781 44.174063 176.565656 C 43.865625 176.736281 43.63375 176.990031 43.38 177.250344 C 42.957813 177.687844 42.588125 178.125344 42.614375 178.746594 z M 45.110312 180.249406 C 44.747188 180.052531 43.743125 179.313156 43.723438 178.746594 C 43.723438 178.740031 43.681875 178.718156 43.695 178.691906 C 44.077813 177.810344 45.049063 177.160656 46.41625 177.160656 C 47.181875 177.160656 47.870938 177.578469 48.317188 178.042219 C 48.713125 178.453469 49.157188 179.286906 49.019375 179.827219 C 48.931875 180.181594 48.56875 180.422219 48.28875 180.538156 C 47.400625 180.905656 45.924063 180.702219 45.110312 180.249406 z M 44.200313 170.173781 C 44.35125 170.195656 44.392813 170.105969 44.480313 170.064406 C 44.933125 169.401594 44.440938 168.874406 43.749688 169.060344 C 43.47625 169.237531 43.285938 169.497844 43.167813 169.839094 C 42.75875 171.055344 43.141563 173.264719 43.94875 173.805031 C 43.75625 173.927531 43.723438 174.467844 43.865625 174.664719 C 43.955313 174.789406 44.255 174.822219 44.50875 174.835344 C 45.2 174.876906 46.075 174.780656 46.737813 174.835344 C 47.980313 174.938156 49.170313 174.938156 49.922813 174.809094 C 50.051875 174.686594 50.154688 174.542219 50.2575 174.391281 C 50.209375 174.187844 50.215938 174.200969 50.23125 173.969094 C 50.135 173.850969 50.00375 173.770031 49.894375 173.660656 C 49.238125 173.756906 48.623438 173.667219 47.88625 173.605969 C 46.7225 173.509719 45.48 173.516281 44.672813 173.024094 C 44.0975 172.483781 44.029688 171.206281 44.200313 170.173781 z M 43.469688 164.125344 C 43.66 164.466594 44.241875 164.479719 44.7625 164.460031 C 45.342188 164.431594 46.10125 164.322219 46.901875 164.225969 C 47.989063 164.090344 49.32125 163.865031 49.874688 163.296281 C 50.544063 162.176281 48.999688 161.635969 48.378438 161.156906 C 49.19875 160.850656 50.093438 160.439406 50.183125 159.680344 C 50.237813 159.216594 49.949063 158.765969 49.642813 158.492531 C 49.4175 158.286906 49.054375 158.100969 48.713125 157.904094 C 48.391563 157.711594 48.015313 157.486281 47.680625 157.383469 C 47.030938 157.186594 46.230313 157.125344 45.50625 157.077219 C 44.843438 157.035656 44.042813 157.116594 43.859063 157.486281 C 43.723438 157.759719 44.077813 158.258469 44.325 158.286906 C 44.480313 158.300031 44.589688 158.142531 44.78875 158.109719 C 45.097188 158.055031 45.34875 158.087844 45.6375 158.109719 C 47.050625 158.219094 48.500938 158.601906 49.150625 159.551281 C 48.780938 160.214094 47.365625 160.111281 47.085625 160.844094 C 46.928125 161.259719 47.243125 161.664406 47.523125 161.874406 C 47.9475 162.195969 48.562188 162.395031 48.91875 162.758156 C 48.021875 163.099406 46.915 163.132219 45.82125 163.296281 C 45.06875 163.405656 44.338125 163.536906 43.59875 163.585031 C 43.504688 163.714094 43.51125 163.945969 43.469688 164.125344 z M 42.614375 152.852062 C 42.642813 153.495187 43.106563 154.171125 43.469688 154.527687 C 43.605313 154.663312 43.8525 154.785812 44.064688 154.949875 C 44.659688 155.402687 45.644063 155.831437 46.497188 155.940812 C 47.919063 156.12675 49.327813 155.606125 49.848438 154.81425 C 49.9425 154.663312 50.121875 154.300187 50.154688 154.074875 C 50.2575 153.3705 49.909688 152.482375 49.588125 151.977062 C 49.192188 151.355812 48.500938 150.71925 47.857813 150.445812 C 46.676563 149.9405 45.10375 150.15925 44.174063 150.671125 C 43.865625 150.84175 43.63375 151.0955 43.38 151.355812 C 42.957813 151.793312 42.588125 152.230812 42.614375 152.852062 z M 45.110313 154.354875 C 44.747188 154.158 43.743125 153.418625 43.723438 152.852062 C 43.723438 152.8455 43.681875 152.823625 43.695 152.797375 C 44.077813 151.915812 45.049063 151.266125 46.41625 151.266125 C 47.181875 151.266125 47.870938 151.683937 48.317188 152.147687 C 48.713125 152.558937 49.157188 153.392375 49.019375 153.932687 C 48.931875 154.287062 48.56875 154.527687 48.28875 154.643625 C 47.400625 155.011125 45.924063 154.807687 45.110313 154.354875 z M 44.200313 144.27925 C 44.35125 144.301125 44.392813 144.211437 44.480313 144.169875 C 44.933125 143.507062 44.440938 142.979875 43.749688 143.165812 C 43.47625 143.343 43.285938 143.603312 43.167813 143.944562 C 42.75875 145.160812 43.141563 147.370187 43.94875 147.9105 C 43.75625 148.033 43.723438 148.573312 43.865625 148.770187 C 43.955313 148.894875 44.255 148.927687 44.50875 148.940812 C 45.2 148.982375 46.075 148.886125 46.737813 148.940812 C 47.980313 149.043625 49.170313 149.043625 49.922813 148.914562 C 50.051875 148.792062 50.154688 148.647687 50.2575 148.49675 C 50.209375 148.293312 50.215938 148.306437 50.23125 148.074562 C 50.135 147.956437 50.00375 147.8755 49.894375 147.766125 C 49.238125 147.862375 48.623438 147.772687 47.88625 147.711437 C 46.7225 147.615187 45.48 147.62175 44.672813 147.129562 C 44.0975 146.58925 44.029688 145.31175 44.200313 144.27925 z M 39.449063 141.1555 C 39.368125 141.313 39.361563 141.730812 39.449063 141.886125 C 40.60625 142.290812 42.47875 142.037062 44.042813 141.96925 C 45.3225 141.914562 46.387813 141.975812 47.577813 141.96925 C 47.9475 141.96925 48.439688 141.956125 48.864063 141.96925 C 49.0675 141.975812 49.456875 141.9955 49.594688 141.940812 C 49.874688 141.824875 50.0125 141.203625 49.75875 140.991437 C 49.28625 140.5955 48.214375 141.011125 47.516563 140.820812 C 47.461875 140.615187 47.394063 140.431437 47.208125 140.348312 C 47.864375 139.337687 48.658438 137.723312 49.874688 137.292375 C 50.03875 137.237687 50.215938 137.237687 50.347188 137.150187 C 50.865625 136.800187 50.421563 136.1855 50.03875 136.028 C 49.6975 136.262062 49.060938 136.362687 48.69125 136.644875 C 48.610313 136.706125 48.575313 136.800187 48.44625 136.896437 C 48.317188 136.992687 48.13125 137.115187 48.021875 137.237687 C 47.420313 137.9355 46.873438 138.762375 46.394375 139.534562 C 45.315938 138.613625 44.38625 137.546125 43.312188 136.616437 C 43.16125 136.658 42.997188 136.623 42.778438 136.706125 C 42.739063 136.883312 42.520313 137.150187 42.559688 137.347062 C 42.588125 137.484875 42.848438 137.6555 42.9775 137.799875 C 43.421563 138.27675 43.894063 138.736125 44.296563 139.138625 C 44.959375 139.801437 45.644063 140.273937 46.114375 140.8755 C 45.081875 140.8755 44.10625 140.862375 43.23125 140.93675 C 41.986563 141.039562 40.372188 140.868937 39.449063 141.1555 z M 49.047813 133.300187 C 47.461875 133.943312 45.364063 133.637062 43.5375 133.553937 C 42.218438 133.492687 40.879688 133.2805 39.648125 133.2455 C 39.497188 133.328625 39.32 133.383312 39.1625 133.451125 C 39.075 133.65675 38.97875 133.862375 38.956875 134.142375 C 38.998438 134.442062 39.204063 135.058937 39.567188 135.0655 C 39.805625 135.072062 40.120625 134.921125 40.16 134.708937 C 40.201563 134.512062 40.030938 134.4355 40.079063 134.271437 C 40.639063 134.313 41.25375 134.40925 41.896875 134.448625 C 42.505 134.490187 43.148125 134.483625 43.769375 134.551437 C 45.554375 134.7505 47.024375 134.840187 48.535938 134.477062 C 49.12875 134.332687 49.739063 134.238625 50.019063 133.862375 C 50.325313 133.444562 50.058438 132.678937 49.607813 132.582687 C 49.246875 132.508312 48.890313 132.958937 49.047813 133.300187 z M 42.614375 128.352062 C 42.642813 128.995187 43.106563 129.671125 43.469688 130.027687 C 43.605313 130.163312 43.8525 130.285812 44.064688 130.449875 C 44.659688 130.902687 45.644063 131.331437 46.497188 131.440812 C 47.919063 131.62675 49.327813 131.106125 49.848438 130.31425 C 49.9425 130.163312 50.121875 129.800187 50.154688 129.574875 C 50.2575 128.8705 49.909688 127.982375 49.588125 127.477062 C 49.192188 126.855812 48.500938 126.21925 47.857813 125.945812 C 46.676563 125.4405 45.10375 125.65925 44.174063 126.171125 C 43.865625 126.34175 43.63375 126.5955 43.38 126.855812 C 42.957813 127.293312 42.588125 127.730812 42.614375 128.352062 z M 45.110313 129.854875 C 44.747188 129.658 43.743125 128.918625 43.723438 128.352062 C 43.723438 128.3455 43.681875 128.323625 43.695 128.297375 C 44.077813 127.415812 45.049063 126.766125 46.41625 126.766125 C 47.181875 126.766125 47.870938 127.183937 48.317188 127.647687 C 48.713125 128.058937 49.157188 128.892375 49.019375 129.432687 C 48.931875 129.787062 48.56875 130.027687 48.28875 130.143625 C 47.400625 130.511125 45.924063 130.307687 45.110313 129.854875 z M 44.535 118.932687 C 44.434375 118.980812 44.47375 119.158 44.425625 119.260812 C 43.8875 119.663312 43.44125 120.293312 43.469688 121.223 C 43.530938 123.491437 46.053125 124.701125 48.25375 124.694562 C 48.63 124.694562 49.12875 124.620187 49.450313 124.394875 C 49.848438 124.112687 50.058438 123.6905 50.189688 123.272687 C 50.19625 121.352062 49.122188 120.518625 48.063438 119.669875 C 48.993125 119.403 50.401875 119.0005 50.135 117.974562 C 49.855 117.620187 49.1375 117.694562 49.0675 118.138625 C 48.391563 118.50175 47.442188 118.753312 46.4775 118.823312 C 45.82125 118.862687 45.123438 118.707375 44.535 118.932687 z M 44.808438 122.178937 C 44.392813 121.522687 44.4475 120.442062 44.94625 119.943312 C 45.309375 120.011125 45.801563 119.90175 46.120938 119.943312 C 46.825313 120.033 47.700313 120.641125 48.275625 121.223 C 48.72625 121.673625 49.465625 122.7455 48.903438 123.491437 C 47.461875 123.880812 45.493125 123.246437 44.808438 122.178937 z M 39.667813 111.467297 C 39.635 111.611672 39.593438 111.946359 39.689688 112.049172 C 40.687188 112.361984 42.327813 112.033859 43.415 112.259172 C 42.710625 113.387922 43.121875 114.871047 43.942188 115.533859 C 45.027188 116.415422 46.53875 116.977609 48.083125 116.642922 C 48.658438 116.415422 49.122188 116.183547 49.430625 115.746047 C 50.277188 114.542922 48.986563 112.978859 48.5075 112.158547 C 48.7 112.116984 48.903438 112.165109 49.012813 112.020734 C 49.095938 111.911359 49.1025 111.480422 49.060938 111.338234 C 49.04125 111.261672 48.98 111.139172 48.931875 111.097609 C 47.892813 110.852609 46.785938 111.174172 45.62875 111.255109 C 45.014063 111.296672 44.296563 111.283547 43.653438 111.228859 C 42.935938 111.165422 42.047813 111.174172 41.301875 111.228859 C 40.722188 111.274797 40.16 111.316359 39.667813 111.467297 z M 45.950313 112.287609 C 46.41625 112.259172 46.895313 112.335734 47.345938 112.259172 C 47.72875 112.915422 48.378438 113.580422 48.616875 114.372297 C 48.671563 114.556047 48.732813 114.803234 48.69125 114.980422 C 48.575313 115.520734 47.639063 115.800734 46.95 115.774484 C 46.020313 115.739484 44.611563 115.028547 44.206875 114.291359 C 44.023125 113.954484 44.058125 113.455734 44.152188 113.024797 C 44.370938 112.574172 45.34875 112.322609 45.950313 112.287609 z " + style="stroke: #ffffff; stroke-width: 4" + id="path7" /> + <path + d="M 40.645625 230.911906 C 40.523125 230.323469 40.262812 229.811594 39.621875 229.811594 C 39.114375 229.811594 38.937188 230.638469 38.937188 230.986281 C 38.937188 231.082531 38.950312 231.172219 38.965625 231.253156 C 39.020312 231.561594 39.053125 232.108469 39.081562 232.749406 C 39.107812 233.405656 39.120937 234.164719 39.149375 234.890969 C 39.204062 236.358781 39.313437 237.774094 39.635 238.082531 C 39.805625 238.253156 40.09875 238.513469 40.37875 238.513469 C 40.88625 238.513469 40.899375 237.535656 40.899375 237.214094 C 40.899375 236.531594 40.770312 235.853469 40.770312 235.184094 C 40.770312 235.155656 40.770312 235.087844 40.783437 235.074719 C 40.879687 234.965344 43.277187 234.917219 43.627187 234.917219 C 45.000937 234.917219 46.368125 235.013469 47.755 235.013469 L 48.44625 235.013469 C 48.72625 235.000344 49.034687 234.971906 49.314687 234.917219 C 49.887813 234.820969 50.38875 234.582531 50.38875 234.035656 C 50.38875 233.460344 49.588125 233.405656 49.183437 233.392531 L 48.739375 233.392531 C 47.496875 233.392531 46.245625 233.591594 44.987812 233.591594 L 44.78875 233.591594 C 44.399375 233.591594 44.016562 233.530344 43.627187 233.530344 C 43.386562 233.530344 42.771875 233.530344 42.183437 233.515031 C 41.581875 233.501906 41.015313 233.475656 40.857812 233.392531 C 40.79 233.366281 40.755 233.228469 40.72875 233.044719 C 40.715625 232.874094 40.72875 232.688156 40.72875 232.620344 C 40.72875 232.408156 40.741875 232.147844 40.72875 231.841594 C 40.72875 231.546281 40.700312 231.218156 40.645625 230.911906 z M 44.200313 224.423781 C 44.35125 224.445656 44.392812 224.355969 44.480312 224.314406 C 44.933125 223.651594 44.440937 223.124406 43.749688 223.310344 C 43.47625 223.487531 43.285938 223.747844 43.167812 224.089094 C 42.75875 225.305344 43.141562 227.514719 43.94875 228.055031 C 43.75625 228.177531 43.723438 228.717844 43.865625 228.914719 C 43.955312 229.039406 44.255 229.072219 44.50875 229.085344 C 45.2 229.126906 46.075 229.030656 46.737812 229.085344 C 47.980312 229.188156 49.170313 229.188156 49.922812 229.059094 C 50.051875 228.936594 50.154688 228.792219 50.2575 228.641281 C 50.209375 228.437844 50.215938 228.450969 50.23125 228.219094 C 50.135 228.100969 50.00375 228.020031 49.894375 227.910656 C 49.238125 228.006906 48.623438 227.917219 47.88625 227.855969 C 46.7225 227.759719 45.48 227.766281 44.672812 227.274094 C 44.0975 226.733781 44.029688 225.456281 44.200313 224.423781 z M 44.535 216.577219 C 44.434375 216.625344 44.47375 216.802531 44.425625 216.905344 C 43.8875 217.307844 43.44125 217.937844 43.469687 218.867531 C 43.530938 221.135969 46.053125 222.345656 48.25375 222.339094 C 48.63 222.339094 49.12875 222.264719 49.450313 222.039406 C 49.848438 221.757219 50.058438 221.335031 50.189687 220.917219 C 50.19625 218.996594 49.122188 218.163156 48.063437 217.314406 C 48.993125 217.047531 50.401875 216.645031 50.135 215.619094 C 49.855 215.264719 49.1375 215.339094 49.0675 215.783156 C 48.391562 216.146281 47.442188 216.397844 46.4775 216.467844 C 45.82125 216.507219 45.123438 216.351906 44.535 216.577219 z M 44.808437 219.823469 C 44.392812 219.167219 44.4475 218.086594 44.94625 217.587844 C 45.309375 217.655656 45.801563 217.546281 46.120937 217.587844 C 46.825313 217.677531 47.700313 218.285656 48.275625 218.867531 C 48.72625 219.318156 49.465625 220.390031 48.903438 221.135969 C 47.461875 221.525344 45.493125 220.890969 44.808437 219.823469 z M 50.1 208.844953 C 50.032187 208.523391 50.1 208.120891 49.909688 207.969953 C 49.752187 207.847453 49.44375 207.934953 49.192188 207.934953 C 47.324063 207.928391 44.917812 207.429641 43.38 208.564953 C 42.887813 208.928078 42.362813 209.700266 42.3825 210.472453 C 42.410938 211.717141 43.2925 212.283703 44.0975 212.843703 C 43.810938 212.856828 43.544063 212.898391 43.347188 213.001203 C 43.2225 213.239641 43.347188 213.692453 43.44125 213.911203 C 44.637813 214.094953 46.715938 214.005266 48.220937 214.059953 C 48.590625 214.075266 49.82 214.300578 50.1 213.972453 C 50.2925 213.747141 50.23125 213.075578 50.067188 212.939953 C 49.894375 212.802141 49.60125 212.865578 49.314687 212.843703 C 48.00875 212.756203 46.982813 212.769328 45.78625 212.283703 C 45.049062 211.981828 43.176563 211.224953 43.723438 210.034953 C 44.180625 209.037453 46.075 208.960891 47.53625 209.063703 C 48.500937 209.131516 49.553125 209.391828 50.1 208.844953 z M 50.141562 204.87382 C 50.051875 204.626633 50.189687 204.40132 50.189687 204.176008 C 50.189687 203.574445 49.868125 202.972883 49.559688 202.570383 C 49.292813 202.220383 48.91875 201.817883 48.535938 201.666945 C 47.989063 201.454758 47.153438 201.49632 46.66125 201.647258 C 46.348438 201.743508 45.875937 202.139445 45.808125 202.49382 C 45.773125 202.679758 45.779688 203.056008 45.85625 203.301008 C 46.011562 203.793195 46.873438 205.051008 45.808125 205.051008 C 45.184688 205.051008 44.583125 204.504133 44.502187 204.02507 C 44.440938 203.642258 44.63125 203.165383 44.75375 202.972883 C 44.856563 202.815383 45.06875 202.795695 45.081875 202.596633 C 45.097188 202.43257 44.769063 202.043195 44.576563 202.023508 C 44.480313 202.016945 44.31625 202.078195 44.255 202.11757 C 43.832813 202.391008 43.544063 203.252883 43.47625 203.773508 C 43.395313 204.359758 43.94875 205.134133 44.303125 205.39882 C 44.515313 205.55632 44.769063 205.768508 45.0075 205.851633 C 45.85625 206.138195 46.621875 206.035383 47.13375 205.475383 C 47.6325 204.62007 47.0375 203.629133 46.7575 202.850383 C 47.01125 202.500383 47.755 202.40632 48.214375 202.596633 C 48.32375 202.644758 48.527188 202.837258 48.610312 202.924758 C 48.754688 203.082258 49.019375 203.410383 49.115625 203.696945 C 49.225 204.040383 49.238125 204.74257 48.91 204.976633 C 48.623438 205.18007 48.137813 205.160383 48.063437 205.427258 C 48.00875 205.61757 48.25375 205.84507 48.336875 206.076945 C 49.157187 206.199445 49.56625 205.707258 49.964375 205.324445 C 49.997188 205.15382 50.058438 205.002883 50.141562 204.87382 z M 49.047812 198.391984 C 47.461875 199.035109 45.364063 198.728859 43.5375 198.645734 C 42.218438 198.584484 40.879688 198.372297 39.648125 198.337297 C 39.497188 198.420422 39.32 198.475109 39.1625 198.542922 C 39.075 198.748547 38.97875 198.954172 38.956875 199.234172 C 38.998438 199.533859 39.204062 200.150734 39.567188 200.157297 C 39.805625 200.163859 40.120625 200.012922 40.16 199.800734 C 40.201563 199.603859 40.030938 199.527297 40.079062 199.363234 C 40.639063 199.404797 41.25375 199.501047 41.896875 199.540422 C 42.505 199.581984 43.148125 199.575422 43.769375 199.643234 C 45.554375 199.842297 47.024375 199.931984 48.535938 199.568859 C 49.12875 199.424484 49.739063 199.330422 50.019063 198.954172 C 50.325313 198.536359 50.058438 197.770734 49.607813 197.674484 C 49.246875 197.600109 48.890313 198.050734 49.047812 198.391984 z M 44.535 191.024484 C 44.434375 191.072609 44.47375 191.249797 44.425625 191.352609 C 43.8875 191.755109 43.44125 192.385109 43.469687 193.314797 C 43.530938 195.583234 46.053125 196.792922 48.25375 196.786359 C 48.63 196.786359 49.12875 196.711984 49.450313 196.486672 C 49.848438 196.204484 50.058438 195.782297 50.189688 195.364484 C 50.19625 193.443859 49.122188 192.610422 48.063437 191.761672 C 48.993125 191.494797 50.401875 191.092297 50.135 190.066359 C 49.855 189.711984 49.1375 189.786359 49.0675 190.230422 C 48.391562 190.593547 47.442188 190.845109 46.4775 190.915109 C 45.82125 190.954484 45.123438 190.799172 44.535 191.024484 z M 44.808438 194.270734 C 44.392813 193.614484 44.4475 192.533859 44.94625 192.035109 C 45.309375 192.102922 45.801563 191.993547 46.120938 192.035109 C 46.825313 192.124797 47.700313 192.732922 48.275625 193.314797 C 48.72625 193.765422 49.465625 194.837297 48.903438 195.583234 C 47.461875 195.972609 45.493125 195.338234 44.808438 194.270734 z M 42.301563 185.643781 C 41.28875 185.405344 40.079062 185.180031 39.10125 185.383469 C 38.956875 185.602219 38.924063 185.930344 39.005 186.068156 C 39.422812 186.772531 41.44625 186.656594 42.301563 186.949719 C 42.402188 187.647531 42.1375 188.397844 42.402188 188.911906 C 42.675625 188.960031 43.16125 189.117531 43.38 188.911906 C 43.614063 188.494094 43.592188 187.824719 43.605313 187.181594 C 44.084375 187.210031 44.795313 187.319406 45.309375 187.345656 C 46.921563 187.428781 48.973438 187.435344 49.778438 186.525344 C 50.347188 185.890969 50.183125 184.652844 49.909688 183.819406 C 49.82 183.539406 49.771875 183.211281 49.649375 183.066906 C 49.402188 182.780344 48.842188 182.970656 48.575313 183.163156 C 48.35 183.812844 49.19875 184.891281 48.870625 185.547531 C 48.671563 185.945656 47.755 186.000344 47.201563 186.039719 C 46.046563 186.122844 44.605 185.985031 43.605313 185.875656 C 43.559375 185.061906 43.769375 184.263469 43.640313 183.395031 C 43.415 183.115031 42.800313 183.217844 42.498438 183.395031 C 42.340938 184.051281 42.3825 184.913156 42.301563 185.643781 z M 42.614375 178.746594 C 42.642813 179.389719 43.106563 180.065656 43.469687 180.422219 C 43.605313 180.557844 43.8525 180.680344 44.064688 180.844406 C 44.659688 181.297219 45.644063 181.725969 46.497188 181.835344 C 47.919063 182.021281 49.327813 181.500656 49.848438 180.708781 C 49.9425 180.557844 50.121875 180.194719 50.154688 179.969406 C 50.2575 179.265031 49.909688 178.376906 49.588125 177.871594 C 49.192188 177.250344 48.500938 176.613781 47.857813 176.340344 C 46.676563 175.835031 45.10375 176.053781 44.174063 176.565656 C 43.865625 176.736281 43.63375 176.990031 43.38 177.250344 C 42.957813 177.687844 42.588125 178.125344 42.614375 178.746594 z M 45.110312 180.249406 C 44.747188 180.052531 43.743125 179.313156 43.723438 178.746594 C 43.723438 178.740031 43.681875 178.718156 43.695 178.691906 C 44.077813 177.810344 45.049063 177.160656 46.41625 177.160656 C 47.181875 177.160656 47.870938 177.578469 48.317188 178.042219 C 48.713125 178.453469 49.157188 179.286906 49.019375 179.827219 C 48.931875 180.181594 48.56875 180.422219 48.28875 180.538156 C 47.400625 180.905656 45.924063 180.702219 45.110312 180.249406 z M 44.200313 170.173781 C 44.35125 170.195656 44.392813 170.105969 44.480313 170.064406 C 44.933125 169.401594 44.440938 168.874406 43.749688 169.060344 C 43.47625 169.237531 43.285938 169.497844 43.167813 169.839094 C 42.75875 171.055344 43.141563 173.264719 43.94875 173.805031 C 43.75625 173.927531 43.723438 174.467844 43.865625 174.664719 C 43.955313 174.789406 44.255 174.822219 44.50875 174.835344 C 45.2 174.876906 46.075 174.780656 46.737813 174.835344 C 47.980313 174.938156 49.170313 174.938156 49.922813 174.809094 C 50.051875 174.686594 50.154688 174.542219 50.2575 174.391281 C 50.209375 174.187844 50.215938 174.200969 50.23125 173.969094 C 50.135 173.850969 50.00375 173.770031 49.894375 173.660656 C 49.238125 173.756906 48.623438 173.667219 47.88625 173.605969 C 46.7225 173.509719 45.48 173.516281 44.672813 173.024094 C 44.0975 172.483781 44.029688 171.206281 44.200313 170.173781 z M 43.469688 164.125344 C 43.66 164.466594 44.241875 164.479719 44.7625 164.460031 C 45.342188 164.431594 46.10125 164.322219 46.901875 164.225969 C 47.989063 164.090344 49.32125 163.865031 49.874688 163.296281 C 50.544063 162.176281 48.999688 161.635969 48.378438 161.156906 C 49.19875 160.850656 50.093438 160.439406 50.183125 159.680344 C 50.237813 159.216594 49.949063 158.765969 49.642813 158.492531 C 49.4175 158.286906 49.054375 158.100969 48.713125 157.904094 C 48.391563 157.711594 48.015313 157.486281 47.680625 157.383469 C 47.030938 157.186594 46.230313 157.125344 45.50625 157.077219 C 44.843438 157.035656 44.042813 157.116594 43.859063 157.486281 C 43.723438 157.759719 44.077813 158.258469 44.325 158.286906 C 44.480313 158.300031 44.589688 158.142531 44.78875 158.109719 C 45.097188 158.055031 45.34875 158.087844 45.6375 158.109719 C 47.050625 158.219094 48.500938 158.601906 49.150625 159.551281 C 48.780938 160.214094 47.365625 160.111281 47.085625 160.844094 C 46.928125 161.259719 47.243125 161.664406 47.523125 161.874406 C 47.9475 162.195969 48.562188 162.395031 48.91875 162.758156 C 48.021875 163.099406 46.915 163.132219 45.82125 163.296281 C 45.06875 163.405656 44.338125 163.536906 43.59875 163.585031 C 43.504688 163.714094 43.51125 163.945969 43.469688 164.125344 z M 42.614375 152.852062 C 42.642813 153.495187 43.106563 154.171125 43.469688 154.527687 C 43.605313 154.663312 43.8525 154.785812 44.064688 154.949875 C 44.659688 155.402687 45.644063 155.831437 46.497188 155.940812 C 47.919063 156.12675 49.327813 155.606125 49.848438 154.81425 C 49.9425 154.663312 50.121875 154.300187 50.154688 154.074875 C 50.2575 153.3705 49.909688 152.482375 49.588125 151.977062 C 49.192188 151.355812 48.500938 150.71925 47.857813 150.445812 C 46.676563 149.9405 45.10375 150.15925 44.174063 150.671125 C 43.865625 150.84175 43.63375 151.0955 43.38 151.355812 C 42.957813 151.793312 42.588125 152.230812 42.614375 152.852062 z M 45.110313 154.354875 C 44.747188 154.158 43.743125 153.418625 43.723438 152.852062 C 43.723438 152.8455 43.681875 152.823625 43.695 152.797375 C 44.077813 151.915812 45.049063 151.266125 46.41625 151.266125 C 47.181875 151.266125 47.870938 151.683937 48.317188 152.147687 C 48.713125 152.558937 49.157188 153.392375 49.019375 153.932687 C 48.931875 154.287062 48.56875 154.527687 48.28875 154.643625 C 47.400625 155.011125 45.924063 154.807687 45.110313 154.354875 z M 44.200313 144.27925 C 44.35125 144.301125 44.392813 144.211437 44.480313 144.169875 C 44.933125 143.507062 44.440938 142.979875 43.749688 143.165812 C 43.47625 143.343 43.285938 143.603312 43.167813 143.944562 C 42.75875 145.160812 43.141563 147.370187 43.94875 147.9105 C 43.75625 148.033 43.723438 148.573312 43.865625 148.770187 C 43.955313 148.894875 44.255 148.927687 44.50875 148.940812 C 45.2 148.982375 46.075 148.886125 46.737813 148.940812 C 47.980313 149.043625 49.170313 149.043625 49.922813 148.914562 C 50.051875 148.792062 50.154688 148.647687 50.2575 148.49675 C 50.209375 148.293312 50.215938 148.306437 50.23125 148.074562 C 50.135 147.956437 50.00375 147.8755 49.894375 147.766125 C 49.238125 147.862375 48.623438 147.772687 47.88625 147.711437 C 46.7225 147.615187 45.48 147.62175 44.672813 147.129562 C 44.0975 146.58925 44.029688 145.31175 44.200313 144.27925 z M 39.449063 141.1555 C 39.368125 141.313 39.361563 141.730812 39.449063 141.886125 C 40.60625 142.290812 42.47875 142.037062 44.042813 141.96925 C 45.3225 141.914562 46.387813 141.975812 47.577813 141.96925 C 47.9475 141.96925 48.439688 141.956125 48.864063 141.96925 C 49.0675 141.975812 49.456875 141.9955 49.594688 141.940812 C 49.874688 141.824875 50.0125 141.203625 49.75875 140.991437 C 49.28625 140.5955 48.214375 141.011125 47.516563 140.820812 C 47.461875 140.615187 47.394063 140.431437 47.208125 140.348312 C 47.864375 139.337687 48.658438 137.723312 49.874688 137.292375 C 50.03875 137.237687 50.215938 137.237687 50.347188 137.150187 C 50.865625 136.800187 50.421563 136.1855 50.03875 136.028 C 49.6975 136.262062 49.060938 136.362687 48.69125 136.644875 C 48.610313 136.706125 48.575313 136.800187 48.44625 136.896437 C 48.317188 136.992687 48.13125 137.115187 48.021875 137.237687 C 47.420313 137.9355 46.873438 138.762375 46.394375 139.534562 C 45.315938 138.613625 44.38625 137.546125 43.312188 136.616437 C 43.16125 136.658 42.997188 136.623 42.778438 136.706125 C 42.739063 136.883312 42.520313 137.150187 42.559688 137.347062 C 42.588125 137.484875 42.848438 137.6555 42.9775 137.799875 C 43.421563 138.27675 43.894063 138.736125 44.296563 139.138625 C 44.959375 139.801437 45.644063 140.273937 46.114375 140.8755 C 45.081875 140.8755 44.10625 140.862375 43.23125 140.93675 C 41.986563 141.039562 40.372188 140.868937 39.449063 141.1555 z M 49.047813 133.300187 C 47.461875 133.943312 45.364063 133.637062 43.5375 133.553937 C 42.218438 133.492687 40.879688 133.2805 39.648125 133.2455 C 39.497188 133.328625 39.32 133.383312 39.1625 133.451125 C 39.075 133.65675 38.97875 133.862375 38.956875 134.142375 C 38.998438 134.442062 39.204063 135.058937 39.567188 135.0655 C 39.805625 135.072062 40.120625 134.921125 40.16 134.708937 C 40.201563 134.512062 40.030938 134.4355 40.079063 134.271437 C 40.639063 134.313 41.25375 134.40925 41.896875 134.448625 C 42.505 134.490187 43.148125 134.483625 43.769375 134.551437 C 45.554375 134.7505 47.024375 134.840187 48.535938 134.477062 C 49.12875 134.332687 49.739063 134.238625 50.019063 133.862375 C 50.325313 133.444562 50.058438 132.678937 49.607813 132.582687 C 49.246875 132.508312 48.890313 132.958937 49.047813 133.300187 z M 42.614375 128.352062 C 42.642813 128.995187 43.106563 129.671125 43.469688 130.027687 C 43.605313 130.163312 43.8525 130.285812 44.064688 130.449875 C 44.659688 130.902687 45.644063 131.331437 46.497188 131.440812 C 47.919063 131.62675 49.327813 131.106125 49.848438 130.31425 C 49.9425 130.163312 50.121875 129.800187 50.154688 129.574875 C 50.2575 128.8705 49.909688 127.982375 49.588125 127.477062 C 49.192188 126.855812 48.500938 126.21925 47.857813 125.945812 C 46.676563 125.4405 45.10375 125.65925 44.174063 126.171125 C 43.865625 126.34175 43.63375 126.5955 43.38 126.855812 C 42.957813 127.293312 42.588125 127.730812 42.614375 128.352062 z M 45.110313 129.854875 C 44.747188 129.658 43.743125 128.918625 43.723438 128.352062 C 43.723438 128.3455 43.681875 128.323625 43.695 128.297375 C 44.077813 127.415812 45.049063 126.766125 46.41625 126.766125 C 47.181875 126.766125 47.870938 127.183937 48.317188 127.647687 C 48.713125 128.058937 49.157188 128.892375 49.019375 129.432687 C 48.931875 129.787062 48.56875 130.027687 48.28875 130.143625 C 47.400625 130.511125 45.924063 130.307687 45.110313 129.854875 z M 44.535 118.932687 C 44.434375 118.980812 44.47375 119.158 44.425625 119.260812 C 43.8875 119.663312 43.44125 120.293312 43.469688 121.223 C 43.530938 123.491437 46.053125 124.701125 48.25375 124.694562 C 48.63 124.694562 49.12875 124.620187 49.450313 124.394875 C 49.848438 124.112687 50.058438 123.6905 50.189688 123.272687 C 50.19625 121.352062 49.122188 120.518625 48.063438 119.669875 C 48.993125 119.403 50.401875 119.0005 50.135 117.974562 C 49.855 117.620187 49.1375 117.694562 49.0675 118.138625 C 48.391563 118.50175 47.442188 118.753312 46.4775 118.823312 C 45.82125 118.862687 45.123438 118.707375 44.535 118.932687 z M 44.808438 122.178937 C 44.392813 121.522687 44.4475 120.442062 44.94625 119.943312 C 45.309375 120.011125 45.801563 119.90175 46.120938 119.943312 C 46.825313 120.033 47.700313 120.641125 48.275625 121.223 C 48.72625 121.673625 49.465625 122.7455 48.903438 123.491437 C 47.461875 123.880812 45.493125 123.246437 44.808438 122.178937 z M 39.667813 111.467297 C 39.635 111.611672 39.593438 111.946359 39.689688 112.049172 C 40.687188 112.361984 42.327813 112.033859 43.415 112.259172 C 42.710625 113.387922 43.121875 114.871047 43.942188 115.533859 C 45.027188 116.415422 46.53875 116.977609 48.083125 116.642922 C 48.658438 116.415422 49.122188 116.183547 49.430625 115.746047 C 50.277188 114.542922 48.986563 112.978859 48.5075 112.158547 C 48.7 112.116984 48.903438 112.165109 49.012813 112.020734 C 49.095938 111.911359 49.1025 111.480422 49.060938 111.338234 C 49.04125 111.261672 48.98 111.139172 48.931875 111.097609 C 47.892813 110.852609 46.785938 111.174172 45.62875 111.255109 C 45.014063 111.296672 44.296563 111.283547 43.653438 111.228859 C 42.935938 111.165422 42.047813 111.174172 41.301875 111.228859 C 40.722188 111.274797 40.16 111.316359 39.667813 111.467297 z M 45.950313 112.287609 C 46.41625 112.259172 46.895313 112.335734 47.345938 112.259172 C 47.72875 112.915422 48.378438 113.580422 48.616875 114.372297 C 48.671563 114.556047 48.732813 114.803234 48.69125 114.980422 C 48.575313 115.520734 47.639063 115.800734 46.95 115.774484 C 46.020313 115.739484 44.611563 115.028547 44.206875 114.291359 C 44.023125 113.954484 44.058125 113.455734 44.152188 113.024797 C 44.370938 112.574172 45.34875 112.322609 45.950313 112.287609 z " + id="path8" /> + </g> + </g> + <g + id="line2d_1"> + <path + d="M 65.62632 -1 L 65.623625 0.00049 L 65.615428 1.001139 L 65.54645 2.003534 L 65.542671 3.004056 L 65.497805 4.005758 L 65.487983 5.006453 L 65.481313 6.007058 L 65.452425 7.008301 L 65.410796 8.00991 L 65.387582 9.010991 L 65.357245 10.012275 L 65.297688 11.0144 L 65.280291 12.015313 L 65.266626 13.016118 L 65.264874 14.016582 L 65.267569 15.016917 L 65.275105 16.017113 L 65.249555 17.018261 L 65.250357 18.018651 L 65.249374 19.019092 L 65.252718 20.019409 L 65.27025 21.019318 L 65.288859 22.019196 L 65.317792 23.018777 L 65.356026 24.018091 L 65.396403 25.017344 L 65.456148 26.016039 L 65.496039 27.015306 L 65.554873 28.014028 L 65.643353 29.011898 L 65.709257 30.010417 L 65.777066 31.008881 L 65.875969 32.972894 L 65.946725 33.977527 L 66.051898 34.974264 L 66.12879 35.972071 L 66.209229 36.969744 L 66.317554 37.966362 L 66.391713 38.964272 L 66.487869 39.96135 L 66.636537 40.956442 L 66.74494 41.953057 L 66.895594 42.948074 L 66.979128 43.94563 L 67.078163 44.942599 L 67.164422 45.940052 L 67.282982 46.936282 L 67.43921 47.931089 L 67.547166 48.927721 L 67.668163 49.923859 L 67.739076 50.921892 L 67.828071 51.919241 L 67.934216 52.915942 L 68.038178 53.912725 L 68.152835 54.909103 L 68.217926 55.907356 L 68.282179 56.905641 L 68.342608 57.90407 L 68.39992 58.902618 L 68.46409 59.900906 L 68.55162 60.89831 L 68.624463 61.89627 L 68.698097 62.8942 L 68.751248 63.892905 L 68.804801 64.891594 L 68.846006 65.890751 L 68.886216 66.889945 L 68.923525 67.889249 L 68.983723 69.531925 L 69.019376 70.519785 L 69.060395 71.518979 L 69.088283 72.518822 L 69.114678 73.518739 L 69.146864 74.518369 L 69.177823 75.518061 L 69.206794 76.51785 L 69.239613 77.517449 L 69.22631 78.51933 L 69.200535 79.521827 L 69.217335 80.522218 L 69.199252 81.524335 L 69.19467 82.525784 L 69.210406 83.526228 L 69.169788 84.529459 L 69.190687 85.529648 L 69.208638 86.529982 L 69.227064 87.530293 L 69.221722 88.53178 L 69.206612 89.53375 L 69.217862 90.534416 L 69.171443 91.537934 L 69.171644 92.539146 L 69.177027 93.540102 L 69.186351 94.540864 L 69.127516 95.544996 L 69.135337 96.545831 L 69.124445 97.583556 L 69.117327 98.589227 L 69.075553 99.593805 L 69.101163 100.594161 L 69.117901 101.595073 L 69.112067 102.597399 L 69.125942 103.59849 L 69.111022 104.601385 L 69.143067 105.601338 L 69.136214 106.603728 L 69.174813 107.60327 L 69.208773 108.603103 L 69.229588 109.60376 L 69.27058 110.603152 L 69.319185 111.602067 L 69.35504 112.601782 L 69.408274 113.600407 L 69.458378 114.599229 L 69.50987 115.597963 L 69.566742 116.596361 L 69.624513 117.594702 L 69.692576 118.592399 L 69.777738 119.739256 L 69.863397 120.750051 L 69.965266 121.745157 L 70.065923 122.740358 L 70.179154 123.734585 L 70.282197 124.729601 L 70.38161 125.724897 L 70.527323 126.716611 L 70.678794 127.707878 L 70.849652 128.697646 L 70.97771 129.690726 L 71.108641 130.683583 L 71.220945 131.677882 L 71.403875 132.666715 L 71.533142 133.659702 L 71.647097 134.653873 L 71.755194 135.648497 L 71.966574 137.587295 L 72.127215 138.57948 L 72.269181 139.570559 L 72.427362 140.560119 L 72.558656 141.552198 L 72.693742 142.543921 L 72.828849 143.535643 L 72.981379 144.525732 L 73.187319 145.510818 L 73.332615 146.501585 L 73.465133 147.493549 L 73.605303 148.484796 L 73.755107 149.475141 L 73.880901 150.467735 L 74.089312 152.304535 L 74.231025 153.284892 L 74.375932 154.274931 L 74.544788 155.262299 L 74.700533 156.25113 L 74.840813 157.241685 L 75.001726 158.229938 L 75.137607 159.220984 L 75.269367 160.212489 L 75.414957 161.202452 L 75.549936 162.193598 L 75.674755 163.185877 L 75.859298 164.669696 L 76.002447 165.64111 L 76.144706 166.631019 L 76.280306 167.6218 L 76.416944 168.612445 L 76.551887 169.603312 L 76.679933 170.595082 L 76.807044 171.586974 L 76.925798 172.57996 L 77.027615 173.575164 L 77.200817 175.235419 L 77.327888 176.208648 L 77.437526 177.203464 L 77.548052 178.198145 L 77.679306 179.189678 L 77.8072 180.181721 L 77.89145 181.180392 L 77.992452 182.17652 L 78.069727 183.17625 L 78.222532 184.390967 L 78.316895 185.377432 L 78.450942 186.369146 L 78.549703 187.367014 L 78.618967 188.370025 L 78.72195 189.367156 L 78.790057 190.370369 L 78.907635 191.364955 L 78.968504 192.43285 L 79.094342 193.429735 L 79.175342 194.433158 L 79.320745 195.423802 L 79.480446 196.41161 L 79.585411 197.410278 L 79.727551 198.401569 L 79.858518 199.513305 L 80.01267 200.518739 L 80.185639 201.504776 L 80.333941 202.496339 L 80.503614 203.483114 L 80.705247 204.462729 L 80.970823 205.771754 L 81.208463 206.77257 L 81.439524 207.745701 L 81.652274 208.723556 L 81.886148 209.695962 L 82.12783 210.666353 L 82.373435 211.635733 L 82.616873 212.605672 L 82.948245 213.880046 L 83.253759 214.875087 L 83.558752 215.827583 L 83.878588 216.775594 L 84.204211 217.721856 L 84.526794 218.669037 L 84.876436 219.608041 L 85.238755 220.732965 L 85.627302 221.692365 L 85.981124 222.62801 L 86.363902 223.553525 L 86.723644 224.487099 L 87.10124 225.414426 L 87.557991 226.62142 L 88.013427 227.542336 L 88.449672 228.444799 L 88.929327 229.329851 L 89.371655 230.229875 L 90.06719 231.653606 L 90.55581 232.534187 L 91.069233 233.399147 L 91.519804 234.292755 L 92.028156 235.160027 L 92.53738 236.036614 L 93.027897 236.890589 L 93.515562 237.764294 L 94.018909 238.629939 L 94.760166 239.985381 L 95.278107 240.812752 L 95.835637 241.645661 L 96.368411 242.49282 L 96.992857 243.476372 L 97.556404 244.262897 L 98.138955 245.077295 L 99.174507 246.611243 L 99.750898 247.370904 L 100.348324 248.172979 L 100.967562 248.959328 L 101.995082 250.359155 L 102.610655 251.072353 L 103.259851 251.833246 L 103.897811 252.603337 L 104.769185 253.663765 L 105.406249 254.356161 L 106.075839 255.098982 L 106.741516 255.845414 L 107.453787 256.664083 L 108.125554 257.332034 L 108.807346 258.065474 L 110.106217 259.391396 L 110.792544 260.059592 L 111.517811 260.749487 L 112.732987 261.89968 L 113.463779 262.529989 L 114.220378 263.186086 L 114.967448 263.854448 L 116.025569 264.749217 L 116.801037 265.344128 L 117.580448 265.975376 L 118.37063 266.591005 L 119.3289 267.32553 L 120.153183 267.876943 L 120.970352 268.457005 L 121.766514 269.071152 L 122.643268 269.682309 L 123.4778 270.250033 L 124.339185 270.758992 L 125.191427 271.284622 L 126.659752 272.223185 L 127.560452 272.701216 L 128.435278 273.188866 L 129.32126 273.653579 L 130.739614 274.441745 L 131.665634 274.88977 L 132.552177 275.359434 L 133.446921 275.810045 L 134.340502 276.263358 L 135.504623 276.789422 L 136.468415 277.17404 L 137.392849 277.556477 L 138.316778 277.940244 L 139.247024 278.307394 L 140.346608 278.752094 L 141.327375 279.094856 L 142.274197 279.416637 L 143.223627 279.730645 L 144.175573 280.037162 L 145.927841 280.610129 L 146.926783 280.8878 L 147.896196 281.135793 L 148.861212 281.39874 L 149.836567 281.626521 L 150.814914 281.844128 L 152.257896 282.239851 L 153.258992 282.46307 L 154.239491 282.665534 L 155.219891 282.868382 L 156.202985 283.060778 L 157.195196 283.217804 L 158.596452 283.534445 L 159.594804 283.70952 L 160.583051 283.873212 L 161.56888 284.047583 L 162.557699 284.208747 L 163.545404 284.374828 L 164.537103 284.52327 L 165.635746 284.651764 L 166.626275 284.79097 L 167.62826 284.878941 L 168.629842 284.968949 L 169.631701 285.05756 L 170.619374 285.217848 L 171.620404 285.310643 L 173.366427 285.578994 L 174.342678 285.706215 L 175.334943 285.836446 L 176.324352 285.983334 L 177.319395 286.097372 L 178.309407 286.240743 L 179.300126 286.37999 L 180.294316 286.498997 L 181.283077 286.649662 L 182.40399 286.819892 L 183.373434 286.949984 L 184.365484 287.077256 L 185.357299 287.206115 L 186.347603 287.345213 L 187.336728 287.492289 L 188.324981 287.64528 L 189.312888 287.800611 L 190.298746 287.969819 L 192.075455 288.257497 L 193.046842 288.392725 L 194.034774 288.551108 L 195.024806 288.692897 L 196.014583 288.836709 L 197.000501 289.011008 L 197.987087 289.180026 L 198.973765 289.348322 L 199.962971 289.496633 L 200.950003 289.662129 L 201.931436 289.871869 L 203.084759 290.060556 L 204.062382 290.230494 L 205.051892 290.38159 L 206.034598 290.595879 L 207.020613 290.779439 L 208.010964 290.922733 L 208.99934 291.084367 L 209.985552 291.266098 L 210.973531 291.431419 L 211.963867 291.574846 L 212.946124 291.793311 L 213.933772 291.961704 L 215.456043 292.176435 L 216.44705 292.366026 L 217.439466 292.494696 L 218.432116 292.620802 L 219.419664 292.802862 L 220.411603 292.936761 L 221.40263 293.080674 L 222.395514 293.204208 L 223.385672 293.357647 L 224.37665 293.502084 L 225.367331 293.649779 L 226.361194 293.762582 L 227.353091 293.896946 L 229.247785 294.116996 L 230.256922 294.211404 L 231.251845 294.315884 L 232.248075 294.403337 L 233.244796 294.484382 L 234.241434 294.566502 L 235.2385 294.643042 L 236.235807 294.71645 L 237.233146 294.789436 L 238.230662 294.86012 L 239.228716 294.923795 L 240.227593 294.976728 L 241.225802 295.038376 L 242.224675 295.091362 L 243.224524 295.131639 L 245.194758 295.251106 L 246.205224 295.285947 L 247.208209 295.271342 L 248.2085 295.298792 L 249.208099 295.337047 L 250.210571 295.330445 L 251.21435 295.303456 L 252.216265 295.305552 L 253.216369 295.335934 L 254.216529 295.36543 L 255.220712 295.332116 L 256.221709 295.34855 L 257.221678 295.381034 L 258.222425 295.401365 L 259.224865 295.395266 L 260.226008 295.409427 L 261.226179 295.438747 L 262.231143 295.393249 L 263.272267 295.426401 L 264.271346 295.442036 L 265.274194 295.414917 L 266.274829 295.42949 L 267.275637 295.440784 L 268.27648 295.451431 L 269.280891 295.39487 L 270.284165 295.359721 L 271.286716 295.338193 L 272.289999 295.302872 L 273.292519 295.281928 L 274.293719 295.285843 L 275.295262 295.283317 L 276.295695 295.301679 L 277.294918 295.342837 L 278.29469 295.373657 L 279.293919 295.414708 L 280.292606 295.465972 L 281.290912 295.524393 L 282.288647 295.593581 L 284.088582 295.705657 L 285.077144 295.779884 L 286.075615 295.83675 L 287.073378 295.909877 L 288.069688 296.016355 L 289.066595 296.109143 L 290.063642 296.198701 L 291.059117 296.324365 L 292.056173 296.413738 L 293.053732 296.491544 L 294.050455 296.588546 L 295.04564 296.720862 L 296.043338 296.795485 L 297.037689 296.946945 L 298.031865 297.102424 L 299.029376 297.181342 L 300.02474 297.309562 L 301.020938 297.41862 L 302.01555 297.564091 L 303.009546 297.72371 L 304.006828 297.807876 L 305.004093 297.89244 L 306.001551 297.97256 L 306.99882 298.057031 L 308.253736 298.18783 L 309.25425 298.299319 L 310.252542 298.365306 L 311.250983 298.427099 L 312.248361 298.518964 L 313.246164 298.598771 L 314.24448 298.66409 L 315.242901 298.726448 L 316.240773 298.804306 L 317.238282 298.892457 L 318.236566 298.958678 L 319.235014 299.020255 L 320.233863 299.070498 L 321.232169 299.136087 L 322.230792 299.192722 L 323.229572 299.244919 L 324.228781 299.284951 L 325.228136 299.320879 L 326.227584 299.354153 L 327.227167 299.383615 L 328.227202 299.400298 L 329.22771 299.403581 L 330.228727 299.392489 L 331.229584 299.385888 L 332.231316 299.354544 L 333.233132 299.32084 L 334.234181 299.308813 L 335.235377 299.292646 L 336.644884 299.302734 L 337.650476 299.261826 L 338.651961 299.223678 L 339.654647 299.143167 L 340.656095 299.106301 L 341.658761 299.026492 L 342.660089 298.993868 L 343.661067 298.973558 L 344.662827 298.925711 L 345.664113 298.894559 L 346.665827 298.848316 L 347.668794 298.757893 L 348.671169 298.688343 L 349.673009 298.637681 L 350.673904 298.620309 L 351.674275 298.621403 L 352.675111 298.606114 L 353.676086 298.585905 L 354.676584 298.582539 L 355.678457 298.530697 L 356.67994 298.492586 L 357.680219 298.496927 L 358.681533 298.464808 L 359.681761 298.470941 L 360.681886 298.480703 L 361.682316 298.479744 L 362.682359 298.492406 L 363.682192 298.512465 L 364.68208 298.530589 L 365.681972 298.548605 L 366.68155 298.577639 L 367.681041 298.609773 L 368.680173 298.654563 L 369.931243 298.70219 L 370.925472 298.735551 L 371.924491 298.789824 L 372.923638 298.838493 L 373.922657 298.892797 L 374.921872 298.938504 L 375.921207 298.978997 L 376.919803 299.0517 L 377.918449 299.122251 L 378.916545 299.216844 L 379.915005 299.295496 L 380.914143 299.34459 L 381.913176 299.398255 L 382.910858 299.510892 L 383.908653 299.618568 L 384.906889 299.707048 L 385.905577 299.775764 L 386.90433 299.841654 L 387.902659 299.926054 L 388.90011 300.048757 L 389.89883 300.116079 L 390.897421 300.189018 L 391.894368 300.333731 L 392.892739 300.416312 L 393.891754 300.470773 L 394.890751 300.526012 L 395.889239 300.603461 L 396.888003 300.668853 L 397.886562 300.743215 L 398.884275 300.854481 L 399.883229 300.911572 L 400.881961 300.978398 L 401.880239 301.064998 L 403.125459 301.168742 L 403.1424 300.429259 " + clip-path="url(#p53efc7421d)" + style="fill: none; stroke: #ffffff; stroke-width: 4; stroke-linecap: square" + id="path9" /> + <path + d="M 65.62632 -1 L 65.623625 0.00049 L 65.615428 1.001139 L 65.54645 2.003534 L 65.542671 3.004056 L 65.497805 4.005758 L 65.487983 5.006453 L 65.481313 6.007058 L 65.452425 7.008301 L 65.410796 8.00991 L 65.387582 9.010991 L 65.357245 10.012275 L 65.297688 11.0144 L 65.280291 12.015313 L 65.266626 13.016118 L 65.264874 14.016582 L 65.267569 15.016917 L 65.275105 16.017113 L 65.249555 17.018261 L 65.250357 18.018651 L 65.249374 19.019092 L 65.252718 20.019409 L 65.27025 21.019318 L 65.288859 22.019196 L 65.317792 23.018777 L 65.356026 24.018091 L 65.396403 25.017344 L 65.456148 26.016039 L 65.496039 27.015306 L 65.554873 28.014028 L 65.643353 29.011898 L 65.709257 30.010417 L 65.777066 31.008881 L 65.875969 32.972894 L 65.946725 33.977527 L 66.051898 34.974264 L 66.12879 35.972071 L 66.209229 36.969744 L 66.317554 37.966362 L 66.391713 38.964272 L 66.487869 39.96135 L 66.636537 40.956442 L 66.74494 41.953057 L 66.895594 42.948074 L 66.979128 43.94563 L 67.078163 44.942599 L 67.164422 45.940052 L 67.282982 46.936282 L 67.43921 47.931089 L 67.547166 48.927721 L 67.668163 49.923859 L 67.739076 50.921892 L 67.828071 51.919241 L 67.934216 52.915942 L 68.038178 53.912725 L 68.152835 54.909103 L 68.217926 55.907356 L 68.282179 56.905641 L 68.342608 57.90407 L 68.39992 58.902618 L 68.46409 59.900906 L 68.55162 60.89831 L 68.624463 61.89627 L 68.698097 62.8942 L 68.751248 63.892905 L 68.804801 64.891594 L 68.846006 65.890751 L 68.886216 66.889945 L 68.923525 67.889249 L 68.983723 69.531925 L 69.019376 70.519785 L 69.060395 71.518979 L 69.088283 72.518822 L 69.114678 73.518739 L 69.146864 74.518369 L 69.177823 75.518061 L 69.206794 76.51785 L 69.239613 77.517449 L 69.22631 78.51933 L 69.200535 79.521827 L 69.217335 80.522218 L 69.199252 81.524335 L 69.19467 82.525784 L 69.210406 83.526228 L 69.169788 84.529459 L 69.190687 85.529648 L 69.208638 86.529982 L 69.227064 87.530293 L 69.221722 88.53178 L 69.206612 89.53375 L 69.217862 90.534416 L 69.171443 91.537934 L 69.171644 92.539146 L 69.177027 93.540102 L 69.186351 94.540864 L 69.127516 95.544996 L 69.135337 96.545831 L 69.124445 97.583556 L 69.117327 98.589227 L 69.075553 99.593805 L 69.101163 100.594161 L 69.117901 101.595073 L 69.112067 102.597399 L 69.125942 103.59849 L 69.111022 104.601385 L 69.143067 105.601338 L 69.136214 106.603728 L 69.174813 107.60327 L 69.208773 108.603103 L 69.229588 109.60376 L 69.27058 110.603152 L 69.319185 111.602067 L 69.35504 112.601782 L 69.408274 113.600407 L 69.458378 114.599229 L 69.50987 115.597963 L 69.566742 116.596361 L 69.624513 117.594702 L 69.692576 118.592399 L 69.777738 119.739256 L 69.863397 120.750051 L 69.965266 121.745157 L 70.065923 122.740358 L 70.179154 123.734585 L 70.282197 124.729601 L 70.38161 125.724897 L 70.527323 126.716611 L 70.678794 127.707878 L 70.849652 128.697646 L 70.97771 129.690726 L 71.108641 130.683583 L 71.220945 131.677882 L 71.403875 132.666715 L 71.533142 133.659702 L 71.647097 134.653873 L 71.755194 135.648497 L 71.966574 137.587295 L 72.127215 138.57948 L 72.269181 139.570559 L 72.427362 140.560119 L 72.558656 141.552198 L 72.693742 142.543921 L 72.828849 143.535643 L 72.981379 144.525732 L 73.187319 145.510818 L 73.332615 146.501585 L 73.465133 147.493549 L 73.605303 148.484796 L 73.755107 149.475141 L 73.880901 150.467735 L 74.089312 152.304535 L 74.231025 153.284892 L 74.375932 154.274931 L 74.544788 155.262299 L 74.700533 156.25113 L 74.840813 157.241685 L 75.001726 158.229938 L 75.137607 159.220984 L 75.269367 160.212489 L 75.414957 161.202452 L 75.549936 162.193598 L 75.674755 163.185877 L 75.859298 164.669696 L 76.002447 165.64111 L 76.144706 166.631019 L 76.280306 167.6218 L 76.416944 168.612445 L 76.551887 169.603312 L 76.679933 170.595082 L 76.807044 171.586974 L 76.925798 172.57996 L 77.027615 173.575164 L 77.200817 175.235419 L 77.327888 176.208648 L 77.437526 177.203464 L 77.548052 178.198145 L 77.679306 179.189678 L 77.8072 180.181721 L 77.89145 181.180392 L 77.992452 182.17652 L 78.069727 183.17625 L 78.222532 184.390967 L 78.316895 185.377432 L 78.450942 186.369146 L 78.549703 187.367014 L 78.618967 188.370025 L 78.72195 189.367156 L 78.790057 190.370369 L 78.907635 191.364955 L 78.968504 192.43285 L 79.094342 193.429735 L 79.175342 194.433158 L 79.320745 195.423802 L 79.480446 196.41161 L 79.585411 197.410278 L 79.727551 198.401569 L 79.858518 199.513305 L 80.01267 200.518739 L 80.185639 201.504776 L 80.333941 202.496339 L 80.503614 203.483114 L 80.705247 204.462729 L 80.970823 205.771754 L 81.208463 206.77257 L 81.439524 207.745701 L 81.652274 208.723556 L 81.886148 209.695962 L 82.12783 210.666353 L 82.373435 211.635733 L 82.616873 212.605672 L 82.948245 213.880046 L 83.253759 214.875087 L 83.558752 215.827583 L 83.878588 216.775594 L 84.204211 217.721856 L 84.526794 218.669037 L 84.876436 219.608041 L 85.238755 220.732965 L 85.627302 221.692365 L 85.981124 222.62801 L 86.363902 223.553525 L 86.723644 224.487099 L 87.10124 225.414426 L 87.557991 226.62142 L 88.013427 227.542336 L 88.449672 228.444799 L 88.929327 229.329851 L 89.371655 230.229875 L 90.06719 231.653606 L 90.55581 232.534187 L 91.069233 233.399147 L 91.519804 234.292755 L 92.028156 235.160027 L 92.53738 236.036614 L 93.027897 236.890589 L 93.515562 237.764294 L 94.018909 238.629939 L 94.760166 239.985381 L 95.278107 240.812752 L 95.835637 241.645661 L 96.368411 242.49282 L 96.992857 243.476372 L 97.556404 244.262897 L 98.138955 245.077295 L 99.174507 246.611243 L 99.750898 247.370904 L 100.348324 248.172979 L 100.967562 248.959328 L 101.995082 250.359155 L 102.610655 251.072353 L 103.259851 251.833246 L 103.897811 252.603337 L 104.769185 253.663765 L 105.406249 254.356161 L 106.075839 255.098982 L 106.741516 255.845414 L 107.453787 256.664083 L 108.125554 257.332034 L 108.807346 258.065474 L 110.106217 259.391396 L 110.792544 260.059592 L 111.517811 260.749487 L 112.732987 261.89968 L 113.463779 262.529989 L 114.220378 263.186086 L 114.967448 263.854448 L 116.025569 264.749217 L 116.801037 265.344128 L 117.580448 265.975376 L 118.37063 266.591005 L 119.3289 267.32553 L 120.153183 267.876943 L 120.970352 268.457005 L 121.766514 269.071152 L 122.643268 269.682309 L 123.4778 270.250033 L 124.339185 270.758992 L 125.191427 271.284622 L 126.659752 272.223185 L 127.560452 272.701216 L 128.435278 273.188866 L 129.32126 273.653579 L 130.739614 274.441745 L 131.665634 274.88977 L 132.552177 275.359434 L 133.446921 275.810045 L 134.340502 276.263358 L 135.504623 276.789422 L 136.468415 277.17404 L 137.392849 277.556477 L 138.316778 277.940244 L 139.247024 278.307394 L 140.346608 278.752094 L 141.327375 279.094856 L 142.274197 279.416637 L 143.223627 279.730645 L 144.175573 280.037162 L 145.927841 280.610129 L 146.926783 280.8878 L 147.896196 281.135793 L 148.861212 281.39874 L 149.836567 281.626521 L 150.814914 281.844128 L 152.257896 282.239851 L 153.258992 282.46307 L 154.239491 282.665534 L 155.219891 282.868382 L 156.202985 283.060778 L 157.195196 283.217804 L 158.596452 283.534445 L 159.594804 283.70952 L 160.583051 283.873212 L 161.56888 284.047583 L 162.557699 284.208747 L 163.545404 284.374828 L 164.537103 284.52327 L 165.635746 284.651764 L 166.626275 284.79097 L 167.62826 284.878941 L 168.629842 284.968949 L 169.631701 285.05756 L 170.619374 285.217848 L 171.620404 285.310643 L 173.366427 285.578994 L 174.342678 285.706215 L 175.334943 285.836446 L 176.324352 285.983334 L 177.319395 286.097372 L 178.309407 286.240743 L 179.300126 286.37999 L 180.294316 286.498997 L 181.283077 286.649662 L 182.40399 286.819892 L 183.373434 286.949984 L 184.365484 287.077256 L 185.357299 287.206115 L 186.347603 287.345213 L 187.336728 287.492289 L 188.324981 287.64528 L 189.312888 287.800611 L 190.298746 287.969819 L 192.075455 288.257497 L 193.046842 288.392725 L 194.034774 288.551108 L 195.024806 288.692897 L 196.014583 288.836709 L 197.000501 289.011008 L 197.987087 289.180026 L 198.973765 289.348322 L 199.962971 289.496633 L 200.950003 289.662129 L 201.931436 289.871869 L 203.084759 290.060556 L 204.062382 290.230494 L 205.051892 290.38159 L 206.034598 290.595879 L 207.020613 290.779439 L 208.010964 290.922733 L 208.99934 291.084367 L 209.985552 291.266098 L 210.973531 291.431419 L 211.963867 291.574846 L 212.946124 291.793311 L 213.933772 291.961704 L 215.456043 292.176435 L 216.44705 292.366026 L 217.439466 292.494696 L 218.432116 292.620802 L 219.419664 292.802862 L 220.411603 292.936761 L 221.40263 293.080674 L 222.395514 293.204208 L 223.385672 293.357647 L 224.37665 293.502084 L 225.367331 293.649779 L 226.361194 293.762582 L 227.353091 293.896946 L 229.247785 294.116996 L 230.256922 294.211404 L 231.251845 294.315884 L 232.248075 294.403337 L 233.244796 294.484382 L 234.241434 294.566502 L 235.2385 294.643042 L 236.235807 294.71645 L 237.233146 294.789436 L 238.230662 294.86012 L 239.228716 294.923795 L 240.227593 294.976728 L 241.225802 295.038376 L 242.224675 295.091362 L 243.224524 295.131639 L 245.194758 295.251106 L 246.205224 295.285947 L 247.208209 295.271342 L 248.2085 295.298792 L 249.208099 295.337047 L 250.210571 295.330445 L 251.21435 295.303456 L 252.216265 295.305552 L 253.216369 295.335934 L 254.216529 295.36543 L 255.220712 295.332116 L 256.221709 295.34855 L 257.221678 295.381034 L 258.222425 295.401365 L 259.224865 295.395266 L 260.226008 295.409427 L 261.226179 295.438747 L 262.231143 295.393249 L 263.272267 295.426401 L 264.271346 295.442036 L 265.274194 295.414917 L 266.274829 295.42949 L 267.275637 295.440784 L 268.27648 295.451431 L 269.280891 295.39487 L 270.284165 295.359721 L 271.286716 295.338193 L 272.289999 295.302872 L 273.292519 295.281928 L 274.293719 295.285843 L 275.295262 295.283317 L 276.295695 295.301679 L 277.294918 295.342837 L 278.29469 295.373657 L 279.293919 295.414708 L 280.292606 295.465972 L 281.290912 295.524393 L 282.288647 295.593581 L 284.088582 295.705657 L 285.077144 295.779884 L 286.075615 295.83675 L 287.073378 295.909877 L 288.069688 296.016355 L 289.066595 296.109143 L 290.063642 296.198701 L 291.059117 296.324365 L 292.056173 296.413738 L 293.053732 296.491544 L 294.050455 296.588546 L 295.04564 296.720862 L 296.043338 296.795485 L 297.037689 296.946945 L 298.031865 297.102424 L 299.029376 297.181342 L 300.02474 297.309562 L 301.020938 297.41862 L 302.01555 297.564091 L 303.009546 297.72371 L 304.006828 297.807876 L 305.004093 297.89244 L 306.001551 297.97256 L 306.99882 298.057031 L 308.253736 298.18783 L 309.25425 298.299319 L 310.252542 298.365306 L 311.250983 298.427099 L 312.248361 298.518964 L 313.246164 298.598771 L 314.24448 298.66409 L 315.242901 298.726448 L 316.240773 298.804306 L 317.238282 298.892457 L 318.236566 298.958678 L 319.235014 299.020255 L 320.233863 299.070498 L 321.232169 299.136087 L 322.230792 299.192722 L 323.229572 299.244919 L 324.228781 299.284951 L 325.228136 299.320879 L 326.227584 299.354153 L 327.227167 299.383615 L 328.227202 299.400298 L 329.22771 299.403581 L 330.228727 299.392489 L 331.229584 299.385888 L 332.231316 299.354544 L 333.233132 299.32084 L 334.234181 299.308813 L 335.235377 299.292646 L 336.644884 299.302734 L 337.650476 299.261826 L 338.651961 299.223678 L 339.654647 299.143167 L 340.656095 299.106301 L 341.658761 299.026492 L 342.660089 298.993868 L 343.661067 298.973558 L 344.662827 298.925711 L 345.664113 298.894559 L 346.665827 298.848316 L 347.668794 298.757893 L 348.671169 298.688343 L 349.673009 298.637681 L 350.673904 298.620309 L 351.674275 298.621403 L 352.675111 298.606114 L 353.676086 298.585905 L 354.676584 298.582539 L 355.678457 298.530697 L 356.67994 298.492586 L 357.680219 298.496927 L 358.681533 298.464808 L 359.681761 298.470941 L 360.681886 298.480703 L 361.682316 298.479744 L 362.682359 298.492406 L 363.682192 298.512465 L 364.68208 298.530589 L 365.681972 298.548605 L 366.68155 298.577639 L 367.681041 298.609773 L 368.680173 298.654563 L 369.931243 298.70219 L 370.925472 298.735551 L 371.924491 298.789824 L 372.923638 298.838493 L 373.922657 298.892797 L 374.921872 298.938504 L 375.921207 298.978997 L 376.919803 299.0517 L 377.918449 299.122251 L 378.916545 299.216844 L 379.915005 299.295496 L 380.914143 299.34459 L 381.913176 299.398255 L 382.910858 299.510892 L 383.908653 299.618568 L 384.906889 299.707048 L 385.905577 299.775764 L 386.90433 299.841654 L 387.902659 299.926054 L 388.90011 300.048757 L 389.89883 300.116079 L 390.897421 300.189018 L 391.894368 300.333731 L 392.892739 300.416312 L 393.891754 300.470773 L 394.890751 300.526012 L 395.889239 300.603461 L 396.888003 300.668853 L 397.886562 300.743215 L 398.884275 300.854481 L 399.883229 300.911572 L 400.881961 300.978398 L 401.880239 301.064998 L 403.125459 301.168742 L 403.1424 300.429259 " + clip-path="url(#p53efc7421d)" + style="fill: none; stroke: #0000ff; stroke-width: 2; stroke-linecap: square" + id="path10" /> + </g> + <g + id="patch_3"> + <path + d="M 59.602588 307.584 L 60.602588 307.615436 L 61.602588 307.652377 L 62.602588 307.750123 L 63.602588 307.782645 L 64.602588 307.85627 L 65.602588 307.894835 L 66.602588 307.930248 L 67.602588 307.987888 L 68.602588 308.058274 L 69.602588 308.110239 L 70.602588 308.169328 L 71.602588 308.257649 L 72.602588 308.303794 L 73.602588 308.346205 L 74.602588 308.376697 L 75.602588 308.402742 L 76.602588 308.423942 L 77.602588 308.478243 L 78.602588 308.506181 L 79.602588 308.535905 L 80.602588 308.5613 L 81.602588 308.5725 L 82.602588 308.582624 L 83.602588 308.58242 L 84.602588 308.57291 L 85.602588 308.561256 L 86.602588 308.530227 L 87.602588 308.519059 L 88.602588 308.488942 L 89.602588 308.429165 L 90.602588 308.391973 L 91.602588 308.352877 L 92.602588 308.310437 L 93.602588 308.277672 L 94.602588 308.210246 L 95.602588 308.17112 L 96.602588 308.128445 L 97.602588 308.057865 L 98.602588 308.021474 L 99.602588 307.963071 L 100.602588 307.852118 L 101.602588 307.78146 L 102.602588 307.66852 L 103.602588 307.622747 L 104.602588 307.561464 L 105.602588 307.512965 L 106.602588 307.432142 L 107.602588 307.313623 L 108.602588 307.243412 L 109.602588 307.16015 L 110.602588 307.127008 L 111.602588 307.075771 L 112.602588 307.007372 L 113.602588 306.941157 L 114.602588 306.86424 L 115.602588 306.836924 L 116.602588 306.810447 L 117.602588 306.787796 L 118.602588 306.768265 L 119.602588 306.741871 L 120.602588 306.6921 L 121.602588 306.657027 L 122.602588 306.621161 L 123.602588 306.605794 L 124.602588 306.590025 L 125.602588 306.586612 L 126.602588 306.584195 L 127.602588 306.584681 L 128.602588 306.58661 L 129.602588 306.599867 L 130.602588 306.608258 L 131.602588 306.629794 L 132.602588 306.652827 L 133.602588 306.67006 L 134.602588 306.688523 L 135.602588 306.708975 L 136.602588 306.725575 L 137.602588 306.788354 L 138.602588 306.863619 L 139.602588 306.896258 L 140.602588 306.963822 L 141.602588 307.017869 L 142.602588 307.051573 L 143.602588 307.141699 L 144.602588 307.170234 L 145.602588 307.20172 L 146.602588 307.232731 L 147.602588 307.287539 L 148.602588 307.352126 L 149.602588 307.390322 L 150.602588 307.486256 L 151.602588 307.535514 L 152.602588 307.579583 L 153.602588 307.619707 L 154.602588 307.728074 L 155.602588 307.769702 L 156.602588 307.831844 L 157.602588 307.901806 L 158.602588 308.00631 L 159.602588 308.043298 L 160.602588 308.089175 L 161.602588 308.15767 L 162.602588 308.206416 L 163.602588 308.284013 L 164.602588 308.314554 L 165.602588 308.384068 L 166.602588 308.408041 L 167.602588 308.436663 L 168.602588 308.478456 L 169.602588 308.500032 L 170.602588 308.51398 L 171.602588 308.540702 L 172.602588 308.550012 L 173.602588 308.562459 L 174.602588 308.573514 L 175.602588 308.579178 L 176.602588 308.583942 L 177.602588 308.578394 L 178.602588 308.565106 L 179.602588 308.557589 L 180.602588 308.532804 L 181.602588 308.509235 L 182.602588 308.473055 L 183.602588 308.447093 L 184.602588 308.424771 L 185.602588 308.356011 L 186.602588 308.281476 L 187.602588 308.187497 L 188.602588 308.136445 L 189.602588 308.082511 L 190.602588 308.04726 L 191.602588 307.941172 L 192.602588 307.888908 L 193.602588 307.852001 L 194.602588 307.82097 L 195.602588 307.759815 L 196.602588 307.692395 L 197.602588 307.643489 L 198.602588 307.578297 L 199.602588 307.540109 L 200.602588 307.498113 L 201.602588 307.456096 L 202.602588 307.39658 L 203.602588 307.28342 L 204.602588 307.231169 L 205.602588 307.191751 L 206.602588 307.14465 L 207.602588 307.08787 L 208.602588 307.055207 L 209.602588 307.019029 L 210.602588 306.986939 L 211.602588 306.952659 L 212.602588 306.894281 L 213.602588 306.849096 L 214.602588 306.819472 L 215.602588 306.769086 L 216.602588 306.743889 L 217.602588 306.722838 L 218.602588 306.68787 L 219.602588 306.66358 L 220.602588 306.649513 L 221.602588 306.630571 L 222.602588 306.61491 L 223.602588 306.602358 L 224.602588 306.596522 L 225.602588 306.58964 L 226.602588 306.584466 L 227.602588 306.586249 L 228.602588 306.588974 L 229.602588 306.600128 L 230.602588 306.628363 L 231.602588 306.672151 L 232.602588 306.69284 L 233.602588 306.733813 L 234.602588 306.773888 L 235.602588 306.792998 L 236.602588 306.815507 L 237.602588 306.882158 L 238.602588 306.931868 L 239.602588 307.005574 L 240.602588 307.036888 L 241.602588 307.11351 L 242.602588 307.151808 L 243.602588 307.225925 L 244.602588 307.329983 L 245.602588 307.399814 L 246.602588 307.505048 L 247.602588 307.560063 L 248.602588 307.683538 L 249.602588 307.754097 L 250.602588 307.869936 L 251.602588 307.920117 L 252.602588 307.955721 L 253.602588 308.047128 L 254.602588 308.100636 L 255.602588 308.188544 L 256.602588 308.257729 L 257.602588 308.304493 L 258.602588 308.376537 L 259.602588 308.426679 L 260.602588 308.444069 L 261.602588 308.471072 L 262.602588 308.490499 L 263.602588 308.509837 L 264.602588 308.548086 L 265.602588 308.564519 L 266.602588 308.572888 L 267.602588 308.577207 L 268.602588 308.583762 L 269.602588 308.581216 L 270.602588 308.575757 L 271.602588 308.559329 L 272.602588 308.527394 L 273.602588 308.489414 L 274.602588 308.45461 L 275.602588 308.391538 L 276.602588 308.370111 L 277.602588 308.319493 L 278.602588 308.294536 L 279.602588 308.238902 L 280.602588 308.207673 L 281.602588 308.157529 L 282.602588 308.125036 L 283.602588 308.044624 L 284.602588 307.975698 L 285.602588 307.860001 L 286.602588 307.784522 L 287.602588 307.668997 L 288.602588 307.589513 L 289.602588 307.481072 L 290.602588 307.441704 L 291.602588 307.338836 L 292.602588 307.239038 L 293.602588 307.193541 L 294.602588 307.159219 L 295.602588 307.107263 L 296.602588 307.067616 L 297.602588 307.032102 L 298.602588 306.964457 L 299.602588 306.925375 L 300.602588 306.874894 L 301.602588 306.825588 L 302.602588 306.774518 L 303.602588 306.730279 L 304.602588 306.708259 L 305.602588 306.692703 L 306.602588 306.650256 L 307.602588 306.635388 L 308.602588 306.61266 L 309.602588 306.592344 L 310.602588 306.586547 L 311.602588 306.584065 L 312.602588 306.587122 L 313.602588 306.598718 L 314.602588 306.615638 L 315.602588 306.647299 L 316.602588 306.661382 L 317.602588 306.714054 L 318.602588 306.763143 L 319.602588 306.817844 L 320.602588 306.862192 L 321.602588 306.932184 L 322.602588 306.982567 L 323.602588 307.036474 L 324.602588 307.105913 L 325.602588 307.163301 L 326.602588 307.213466 L 327.602588 307.290628 L 328.602588 307.348818 L 329.602588 307.409456 L 330.602588 307.446657 L 331.602588 307.511749 L 332.602588 307.616879 L 333.602588 307.677181 L 334.602588 307.773503 L 335.602588 307.805506 L 336.602588 307.856523 L 337.602588 307.973315 L 338.602588 308.008762 L 339.602588 308.064642 L 340.602588 308.095018 L 341.602588 308.183404 L 342.602588 308.228168 L 343.602588 308.309056 L 344.602588 308.369202 L 345.602588 308.432288 L 346.602588 308.455236 L 347.602588 308.471406 L 348.602588 308.500335 L 349.602588 308.530687 L 350.602588 308.543261 L 351.602588 308.56814 L 352.602588 308.580224 L 353.602588 308.583986 L 354.602588 308.57955 L 355.602588 308.567211 L 356.602588 308.552798 L 357.602588 308.536725 L 358.602588 308.501204 L 359.602588 308.48127 L 360.602588 308.424681 L 361.602588 308.357487 L 362.602588 308.330117 L 363.602588 308.295969 L 364.602588 308.247289 L 365.602588 308.199004 L 366.602588 308.139927 L 367.602588 308.044322 L 368.602588 308.001182 L 369.602588 307.951334 L 370.602588 307.8928 L 371.602588 307.845214 L 372.602588 307.784086 L 373.602588 307.728001 L 374.602588 307.65383 L 375.602588 307.536592 L 376.602588 307.480868 L 377.602588 307.372642 L 378.602588 307.266492 L 379.602588 307.15892 L 380.602588 307.124412 L 381.602588 307.021105 L 382.602588 306.945381 L 383.602588 306.905946 L 384.602588 306.866562 L 385.602588 306.84408 L 386.602588 306.788267 L 387.602588 306.762215 L 388.602588 306.73198 L 389.602588 306.681209 L 390.602588 306.662558 L 391.602588 306.640849 L 392.602588 306.628203 L 393.602588 306.60921 L 394.602588 306.59182 L 395.602588 306.584782 L 396.602588 306.585806 L 397.602588 306.59281 L 398.602588 306.60218 L 399.602588 306.625578 L 400.602588 306.650661 L 401.602588 306.66306 L 402.602588 306.696153 L 403.602588 306.71252 L 404.602588 306.730925 L 405.602588 306.780062 L 406.602588 306.823875 L 407.602588 306.86696 L 408.602588 306.889901 L 409.602588 306.930164 L 411.599771 307.015024 " + style="fill: none; stroke: #ffffff; stroke-width: 4; stroke-linecap: round" + id="path11" /> + <path + d="M 59.602588 307.584 L 60.602588 307.615436 L 61.602588 307.652377 L 62.602588 307.750123 L 63.602588 307.782645 L 64.602588 307.85627 L 65.602588 307.894835 L 66.602588 307.930248 L 67.602588 307.987888 L 68.602588 308.058274 L 69.602588 308.110239 L 70.602588 308.169328 L 71.602588 308.257649 L 72.602588 308.303794 L 73.602588 308.346205 L 74.602588 308.376697 L 75.602588 308.402742 L 76.602588 308.423942 L 77.602588 308.478243 L 78.602588 308.506181 L 79.602588 308.535905 L 80.602588 308.5613 L 81.602588 308.5725 L 82.602588 308.582624 L 83.602588 308.58242 L 84.602588 308.57291 L 85.602588 308.561256 L 86.602588 308.530227 L 87.602588 308.519059 L 88.602588 308.488942 L 89.602588 308.429165 L 90.602588 308.391973 L 91.602588 308.352877 L 92.602588 308.310437 L 93.602588 308.277672 L 94.602588 308.210246 L 95.602588 308.17112 L 96.602588 308.128445 L 97.602588 308.057865 L 98.602588 308.021474 L 99.602588 307.963071 L 100.602588 307.852118 L 101.602588 307.78146 L 102.602588 307.66852 L 103.602588 307.622747 L 104.602588 307.561464 L 105.602588 307.512965 L 106.602588 307.432142 L 107.602588 307.313623 L 108.602588 307.243412 L 109.602588 307.16015 L 110.602588 307.127008 L 111.602588 307.075771 L 112.602588 307.007372 L 113.602588 306.941157 L 114.602588 306.86424 L 115.602588 306.836924 L 116.602588 306.810447 L 117.602588 306.787796 L 118.602588 306.768265 L 119.602588 306.741871 L 120.602588 306.6921 L 121.602588 306.657027 L 122.602588 306.621161 L 123.602588 306.605794 L 124.602588 306.590025 L 125.602588 306.586612 L 126.602588 306.584195 L 127.602588 306.584681 L 128.602588 306.58661 L 129.602588 306.599867 L 130.602588 306.608258 L 131.602588 306.629794 L 132.602588 306.652827 L 133.602588 306.67006 L 134.602588 306.688523 L 135.602588 306.708975 L 136.602588 306.725575 L 137.602588 306.788354 L 138.602588 306.863619 L 139.602588 306.896258 L 140.602588 306.963822 L 141.602588 307.017869 L 142.602588 307.051573 L 143.602588 307.141699 L 144.602588 307.170234 L 145.602588 307.20172 L 146.602588 307.232731 L 147.602588 307.287539 L 148.602588 307.352126 L 149.602588 307.390322 L 150.602588 307.486256 L 151.602588 307.535514 L 152.602588 307.579583 L 153.602588 307.619707 L 154.602588 307.728074 L 155.602588 307.769702 L 156.602588 307.831844 L 157.602588 307.901806 L 158.602588 308.00631 L 159.602588 308.043298 L 160.602588 308.089175 L 161.602588 308.15767 L 162.602588 308.206416 L 163.602588 308.284013 L 164.602588 308.314554 L 165.602588 308.384068 L 166.602588 308.408041 L 167.602588 308.436663 L 168.602588 308.478456 L 169.602588 308.500032 L 170.602588 308.51398 L 171.602588 308.540702 L 172.602588 308.550012 L 173.602588 308.562459 L 174.602588 308.573514 L 175.602588 308.579178 L 176.602588 308.583942 L 177.602588 308.578394 L 178.602588 308.565106 L 179.602588 308.557589 L 180.602588 308.532804 L 181.602588 308.509235 L 182.602588 308.473055 L 183.602588 308.447093 L 184.602588 308.424771 L 185.602588 308.356011 L 186.602588 308.281476 L 187.602588 308.187497 L 188.602588 308.136445 L 189.602588 308.082511 L 190.602588 308.04726 L 191.602588 307.941172 L 192.602588 307.888908 L 193.602588 307.852001 L 194.602588 307.82097 L 195.602588 307.759815 L 196.602588 307.692395 L 197.602588 307.643489 L 198.602588 307.578297 L 199.602588 307.540109 L 200.602588 307.498113 L 201.602588 307.456096 L 202.602588 307.39658 L 203.602588 307.28342 L 204.602588 307.231169 L 205.602588 307.191751 L 206.602588 307.14465 L 207.602588 307.08787 L 208.602588 307.055207 L 209.602588 307.019029 L 210.602588 306.986939 L 211.602588 306.952659 L 212.602588 306.894281 L 213.602588 306.849096 L 214.602588 306.819472 L 215.602588 306.769086 L 216.602588 306.743889 L 217.602588 306.722838 L 218.602588 306.68787 L 219.602588 306.66358 L 220.602588 306.649513 L 221.602588 306.630571 L 222.602588 306.61491 L 223.602588 306.602358 L 224.602588 306.596522 L 225.602588 306.58964 L 226.602588 306.584466 L 227.602588 306.586249 L 228.602588 306.588974 L 229.602588 306.600128 L 230.602588 306.628363 L 231.602588 306.672151 L 232.602588 306.69284 L 233.602588 306.733813 L 234.602588 306.773888 L 235.602588 306.792998 L 236.602588 306.815507 L 237.602588 306.882158 L 238.602588 306.931868 L 239.602588 307.005574 L 240.602588 307.036888 L 241.602588 307.11351 L 242.602588 307.151808 L 243.602588 307.225925 L 244.602588 307.329983 L 245.602588 307.399814 L 246.602588 307.505048 L 247.602588 307.560063 L 248.602588 307.683538 L 249.602588 307.754097 L 250.602588 307.869936 L 251.602588 307.920117 L 252.602588 307.955721 L 253.602588 308.047128 L 254.602588 308.100636 L 255.602588 308.188544 L 256.602588 308.257729 L 257.602588 308.304493 L 258.602588 308.376537 L 259.602588 308.426679 L 260.602588 308.444069 L 261.602588 308.471072 L 262.602588 308.490499 L 263.602588 308.509837 L 264.602588 308.548086 L 265.602588 308.564519 L 266.602588 308.572888 L 267.602588 308.577207 L 268.602588 308.583762 L 269.602588 308.581216 L 270.602588 308.575757 L 271.602588 308.559329 L 272.602588 308.527394 L 273.602588 308.489414 L 274.602588 308.45461 L 275.602588 308.391538 L 276.602588 308.370111 L 277.602588 308.319493 L 278.602588 308.294536 L 279.602588 308.238902 L 280.602588 308.207673 L 281.602588 308.157529 L 282.602588 308.125036 L 283.602588 308.044624 L 284.602588 307.975698 L 285.602588 307.860001 L 286.602588 307.784522 L 287.602588 307.668997 L 288.602588 307.589513 L 289.602588 307.481072 L 290.602588 307.441704 L 291.602588 307.338836 L 292.602588 307.239038 L 293.602588 307.193541 L 294.602588 307.159219 L 295.602588 307.107263 L 296.602588 307.067616 L 297.602588 307.032102 L 298.602588 306.964457 L 299.602588 306.925375 L 300.602588 306.874894 L 301.602588 306.825588 L 302.602588 306.774518 L 303.602588 306.730279 L 304.602588 306.708259 L 305.602588 306.692703 L 306.602588 306.650256 L 307.602588 306.635388 L 308.602588 306.61266 L 309.602588 306.592344 L 310.602588 306.586547 L 311.602588 306.584065 L 312.602588 306.587122 L 313.602588 306.598718 L 314.602588 306.615638 L 315.602588 306.647299 L 316.602588 306.661382 L 317.602588 306.714054 L 318.602588 306.763143 L 319.602588 306.817844 L 320.602588 306.862192 L 321.602588 306.932184 L 322.602588 306.982567 L 323.602588 307.036474 L 324.602588 307.105913 L 325.602588 307.163301 L 326.602588 307.213466 L 327.602588 307.290628 L 328.602588 307.348818 L 329.602588 307.409456 L 330.602588 307.446657 L 331.602588 307.511749 L 332.602588 307.616879 L 333.602588 307.677181 L 334.602588 307.773503 L 335.602588 307.805506 L 336.602588 307.856523 L 337.602588 307.973315 L 338.602588 308.008762 L 339.602588 308.064642 L 340.602588 308.095018 L 341.602588 308.183404 L 342.602588 308.228168 L 343.602588 308.309056 L 344.602588 308.369202 L 345.602588 308.432288 L 346.602588 308.455236 L 347.602588 308.471406 L 348.602588 308.500335 L 349.602588 308.530687 L 350.602588 308.543261 L 351.602588 308.56814 L 352.602588 308.580224 L 353.602588 308.583986 L 354.602588 308.57955 L 355.602588 308.567211 L 356.602588 308.552798 L 357.602588 308.536725 L 358.602588 308.501204 L 359.602588 308.48127 L 360.602588 308.424681 L 361.602588 308.357487 L 362.602588 308.330117 L 363.602588 308.295969 L 364.602588 308.247289 L 365.602588 308.199004 L 366.602588 308.139927 L 367.602588 308.044322 L 368.602588 308.001182 L 369.602588 307.951334 L 370.602588 307.8928 L 371.602588 307.845214 L 372.602588 307.784086 L 373.602588 307.728001 L 374.602588 307.65383 L 375.602588 307.536592 L 376.602588 307.480868 L 377.602588 307.372642 L 378.602588 307.266492 L 379.602588 307.15892 L 380.602588 307.124412 L 381.602588 307.021105 L 382.602588 306.945381 L 383.602588 306.905946 L 384.602588 306.866562 L 385.602588 306.84408 L 386.602588 306.788267 L 387.602588 306.762215 L 388.602588 306.73198 L 389.602588 306.681209 L 390.602588 306.662558 L 391.602588 306.640849 L 392.602588 306.628203 L 393.602588 306.60921 L 394.602588 306.59182 L 395.602588 306.584782 L 396.602588 306.585806 L 397.602588 306.59281 L 398.602588 306.60218 L 399.602588 306.625578 L 400.602588 306.650661 L 401.602588 306.66306 L 402.602588 306.696153 L 403.602588 306.71252 L 404.602588 306.730925 L 405.602588 306.780062 L 406.602588 306.823875 L 407.602588 306.86696 L 408.602588 306.889901 L 409.602588 306.930164 L 411.599771 307.015024 " + style="fill: none; stroke: #000000; stroke-linecap: round" + id="path12" /> + <path + d="M 405.999771 304.784 L 406.880139 305.259331 L 407.758046 305.739585 L 408.608759 306.274226 L 409.488643 306.750528 L 410.350144 307.263593 L 411.460761 307.862019 L 410.550496 307.72152 L 409.630292 308.117178 L 408.704387 308.501437 L 407.786721 308.902172 L 406.865868 309.296534 L 405.698505 309.78147 " + style="fill: none; stroke: #ffffff; stroke-width: 4; stroke-linecap: round" + id="path13" /> + <path + d="M 405.999771 304.784 L 406.880139 305.259331 L 407.758046 305.739585 L 408.608759 306.274226 L 409.488643 306.750528 L 410.350144 307.263593 L 411.460761 307.862019 L 410.550496 307.72152 L 409.630292 308.117178 L 408.704387 308.501437 L 407.786721 308.902172 L 406.865868 309.296534 L 405.698505 309.78147 " + style="fill: none; stroke: #000000; stroke-linecap: round" + id="path14" /> + </g> + <g + id="patch_4"> + <path + d="M 57.6 305.58215 L 57.631436 304.58215 L 57.668377 303.58215 L 57.766123 302.58215 L 57.798645 301.58215 L 57.87227 300.58215 L 57.910835 299.58215 L 57.946248 298.58215 L 58.003888 297.58215 L 58.074274 296.58215 L 58.126239 295.58215 L 58.185328 294.58215 L 58.273649 293.58215 L 58.319794 292.58215 L 58.362205 291.58215 L 58.392697 290.58215 L 58.418742 289.58215 L 58.439942 288.58215 L 58.494243 287.58215 L 58.522181 286.58215 L 58.551905 285.58215 L 58.5773 284.58215 L 58.5885 283.58215 L 58.598624 282.58215 L 58.59842 281.58215 L 58.58891 280.58215 L 58.577256 279.58215 L 58.546227 278.58215 L 58.535059 277.58215 L 58.504942 276.58215 L 58.445165 275.58215 L 58.407973 274.58215 L 58.368877 273.58215 L 58.326437 272.58215 L 58.293672 271.58215 L 58.226246 270.58215 L 58.18712 269.58215 L 58.144445 268.58215 L 58.073865 267.58215 L 58.037474 266.58215 L 57.979071 265.58215 L 57.868118 264.58215 L 57.79746 263.58215 L 57.68452 262.58215 L 57.638747 261.58215 L 57.577464 260.58215 L 57.528965 259.58215 L 57.448142 258.58215 L 57.329623 257.58215 L 57.259412 256.58215 L 57.17615 255.58215 L 57.143008 254.58215 L 57.091771 253.58215 L 57.023372 252.58215 L 56.957157 251.58215 L 56.88024 250.58215 L 56.852924 249.58215 L 56.826447 248.58215 L 56.803796 247.58215 L 56.784265 246.58215 L 56.757871 245.58215 L 56.7081 244.58215 L 56.673027 243.58215 L 56.637161 242.58215 L 56.621794 241.58215 L 56.606025 240.58215 L 56.602612 239.58215 L 56.600195 238.58215 L 56.600681 237.58215 L 56.60261 236.58215 L 56.615867 235.58215 L 56.624258 234.58215 L 56.645794 233.58215 L 56.668827 232.58215 L 56.68606 231.58215 L 56.704523 230.58215 L 56.724975 229.58215 L 56.741575 228.58215 L 56.804354 227.58215 L 56.879619 226.58215 L 56.912258 225.58215 L 56.979822 224.58215 L 57.033869 223.58215 L 57.067573 222.58215 L 57.157699 221.58215 L 57.186234 220.58215 L 57.21772 219.58215 L 57.248731 218.58215 L 57.303539 217.58215 L 57.368126 216.58215 L 57.406322 215.58215 L 57.502256 214.58215 L 57.551514 213.58215 L 57.595583 212.58215 L 57.635707 211.58215 L 57.744074 210.58215 L 57.785702 209.58215 L 57.847844 208.58215 L 57.917806 207.58215 L 58.02231 206.58215 L 58.059298 205.58215 L 58.105175 204.58215 L 58.17367 203.58215 L 58.222416 202.58215 L 58.300013 201.58215 L 58.330554 200.58215 L 58.400068 199.58215 L 58.424041 198.58215 L 58.452663 197.58215 L 58.494456 196.58215 L 58.516032 195.58215 L 58.52998 194.58215 L 58.556702 193.58215 L 58.566012 192.58215 L 58.578459 191.58215 L 58.589514 190.58215 L 58.595178 189.58215 L 58.599942 188.58215 L 58.594394 187.58215 L 58.581106 186.58215 L 58.573589 185.58215 L 58.548804 184.58215 L 58.525235 183.58215 L 58.489055 182.58215 L 58.463093 181.58215 L 58.440771 180.58215 L 58.372011 179.58215 L 58.297476 178.58215 L 58.203497 177.58215 L 58.152445 176.58215 L 58.098511 175.58215 L 58.06326 174.58215 L 57.957172 173.58215 L 57.904908 172.58215 L 57.868001 171.58215 L 57.83697 170.58215 L 57.775815 169.58215 L 57.708395 168.58215 L 57.659489 167.58215 L 57.594297 166.58215 L 57.556109 165.58215 L 57.514113 164.58215 L 57.472096 163.58215 L 57.41258 162.58215 L 57.29942 161.58215 L 57.247169 160.58215 L 57.207751 159.58215 L 57.16065 158.58215 L 57.10387 157.58215 L 57.071207 156.58215 L 57.035029 155.58215 L 57.002939 154.58215 L 56.968659 153.58215 L 56.910281 152.58215 L 56.865096 151.58215 L 56.835472 150.58215 L 56.785086 149.58215 L 56.759889 148.58215 L 56.738838 147.58215 L 56.70387 146.58215 L 56.67958 145.58215 L 56.665513 144.58215 L 56.646571 143.58215 L 56.63091 142.58215 L 56.618358 141.58215 L 56.612522 140.58215 L 56.60564 139.58215 L 56.600466 138.58215 L 56.602249 137.58215 L 56.604974 136.58215 L 56.616128 135.58215 L 56.644363 134.58215 L 56.688151 133.58215 L 56.70884 132.58215 L 56.749813 131.58215 L 56.789888 130.58215 L 56.808998 129.58215 L 56.831507 128.58215 L 56.898158 127.58215 L 56.947868 126.58215 L 57.021574 125.58215 L 57.052888 124.58215 L 57.12951 123.58215 L 57.167808 122.58215 L 57.241925 121.58215 L 57.345983 120.58215 L 57.415814 119.58215 L 57.521048 118.58215 L 57.576063 117.58215 L 57.699538 116.58215 L 57.770097 115.58215 L 57.885936 114.58215 L 57.936117 113.58215 L 57.971721 112.58215 L 58.063128 111.58215 L 58.116636 110.58215 L 58.204544 109.58215 L 58.273729 108.58215 L 58.320493 107.58215 L 58.392537 106.58215 L 58.442679 105.58215 L 58.460069 104.58215 L 58.487072 103.58215 L 58.506499 102.58215 L 58.525837 101.58215 L 58.564086 100.58215 L 58.580519 99.58215 L 58.588888 98.58215 L 58.593207 97.58215 L 58.599762 96.58215 L 58.597216 95.58215 L 58.591757 94.58215 L 58.575329 93.58215 L 58.543394 92.58215 L 58.505414 91.58215 L 58.47061 90.58215 L 58.407538 89.58215 L 58.386111 88.58215 L 58.335493 87.58215 L 58.310536 86.58215 L 58.254902 85.58215 L 58.223673 84.58215 L 58.173529 83.58215 L 58.141036 82.58215 L 58.060624 81.58215 L 57.991698 80.58215 L 57.876001 79.58215 L 57.800522 78.58215 L 57.684997 77.58215 L 57.605513 76.58215 L 57.497072 75.58215 L 57.457704 74.58215 L 57.354836 73.58215 L 57.255038 72.58215 L 57.209541 71.58215 L 57.175219 70.58215 L 57.123263 69.58215 L 57.083616 68.58215 L 57.048102 67.58215 L 56.980457 66.58215 L 56.941375 65.58215 L 56.890894 64.58215 L 56.841588 63.58215 L 56.790518 62.58215 L 56.746279 61.58215 L 56.724259 60.58215 L 56.708703 59.58215 L 56.666256 58.58215 L 56.651388 57.58215 L 56.62866 56.58215 L 56.608344 55.58215 L 56.602547 54.58215 L 56.600065 53.58215 L 56.603122 52.58215 L 56.614718 51.58215 L 56.631638 50.58215 L 56.663299 49.58215 L 56.677382 48.58215 L 56.730054 47.58215 L 56.779143 46.58215 L 56.833844 44.592945 " + style="fill: none; stroke: #ffffff; stroke-width: 4; stroke-linecap: round" + id="path15" /> + <path + d="M 57.6 305.58215 L 57.631436 304.58215 L 57.668377 303.58215 L 57.766123 302.58215 L 57.798645 301.58215 L 57.87227 300.58215 L 57.910835 299.58215 L 57.946248 298.58215 L 58.003888 297.58215 L 58.074274 296.58215 L 58.126239 295.58215 L 58.185328 294.58215 L 58.273649 293.58215 L 58.319794 292.58215 L 58.362205 291.58215 L 58.392697 290.58215 L 58.418742 289.58215 L 58.439942 288.58215 L 58.494243 287.58215 L 58.522181 286.58215 L 58.551905 285.58215 L 58.5773 284.58215 L 58.5885 283.58215 L 58.598624 282.58215 L 58.59842 281.58215 L 58.58891 280.58215 L 58.577256 279.58215 L 58.546227 278.58215 L 58.535059 277.58215 L 58.504942 276.58215 L 58.445165 275.58215 L 58.407973 274.58215 L 58.368877 273.58215 L 58.326437 272.58215 L 58.293672 271.58215 L 58.226246 270.58215 L 58.18712 269.58215 L 58.144445 268.58215 L 58.073865 267.58215 L 58.037474 266.58215 L 57.979071 265.58215 L 57.868118 264.58215 L 57.79746 263.58215 L 57.68452 262.58215 L 57.638747 261.58215 L 57.577464 260.58215 L 57.528965 259.58215 L 57.448142 258.58215 L 57.329623 257.58215 L 57.259412 256.58215 L 57.17615 255.58215 L 57.143008 254.58215 L 57.091771 253.58215 L 57.023372 252.58215 L 56.957157 251.58215 L 56.88024 250.58215 L 56.852924 249.58215 L 56.826447 248.58215 L 56.803796 247.58215 L 56.784265 246.58215 L 56.757871 245.58215 L 56.7081 244.58215 L 56.673027 243.58215 L 56.637161 242.58215 L 56.621794 241.58215 L 56.606025 240.58215 L 56.602612 239.58215 L 56.600195 238.58215 L 56.600681 237.58215 L 56.60261 236.58215 L 56.615867 235.58215 L 56.624258 234.58215 L 56.645794 233.58215 L 56.668827 232.58215 L 56.68606 231.58215 L 56.704523 230.58215 L 56.724975 229.58215 L 56.741575 228.58215 L 56.804354 227.58215 L 56.879619 226.58215 L 56.912258 225.58215 L 56.979822 224.58215 L 57.033869 223.58215 L 57.067573 222.58215 L 57.157699 221.58215 L 57.186234 220.58215 L 57.21772 219.58215 L 57.248731 218.58215 L 57.303539 217.58215 L 57.368126 216.58215 L 57.406322 215.58215 L 57.502256 214.58215 L 57.551514 213.58215 L 57.595583 212.58215 L 57.635707 211.58215 L 57.744074 210.58215 L 57.785702 209.58215 L 57.847844 208.58215 L 57.917806 207.58215 L 58.02231 206.58215 L 58.059298 205.58215 L 58.105175 204.58215 L 58.17367 203.58215 L 58.222416 202.58215 L 58.300013 201.58215 L 58.330554 200.58215 L 58.400068 199.58215 L 58.424041 198.58215 L 58.452663 197.58215 L 58.494456 196.58215 L 58.516032 195.58215 L 58.52998 194.58215 L 58.556702 193.58215 L 58.566012 192.58215 L 58.578459 191.58215 L 58.589514 190.58215 L 58.595178 189.58215 L 58.599942 188.58215 L 58.594394 187.58215 L 58.581106 186.58215 L 58.573589 185.58215 L 58.548804 184.58215 L 58.525235 183.58215 L 58.489055 182.58215 L 58.463093 181.58215 L 58.440771 180.58215 L 58.372011 179.58215 L 58.297476 178.58215 L 58.203497 177.58215 L 58.152445 176.58215 L 58.098511 175.58215 L 58.06326 174.58215 L 57.957172 173.58215 L 57.904908 172.58215 L 57.868001 171.58215 L 57.83697 170.58215 L 57.775815 169.58215 L 57.708395 168.58215 L 57.659489 167.58215 L 57.594297 166.58215 L 57.556109 165.58215 L 57.514113 164.58215 L 57.472096 163.58215 L 57.41258 162.58215 L 57.29942 161.58215 L 57.247169 160.58215 L 57.207751 159.58215 L 57.16065 158.58215 L 57.10387 157.58215 L 57.071207 156.58215 L 57.035029 155.58215 L 57.002939 154.58215 L 56.968659 153.58215 L 56.910281 152.58215 L 56.865096 151.58215 L 56.835472 150.58215 L 56.785086 149.58215 L 56.759889 148.58215 L 56.738838 147.58215 L 56.70387 146.58215 L 56.67958 145.58215 L 56.665513 144.58215 L 56.646571 143.58215 L 56.63091 142.58215 L 56.618358 141.58215 L 56.612522 140.58215 L 56.60564 139.58215 L 56.600466 138.58215 L 56.602249 137.58215 L 56.604974 136.58215 L 56.616128 135.58215 L 56.644363 134.58215 L 56.688151 133.58215 L 56.70884 132.58215 L 56.749813 131.58215 L 56.789888 130.58215 L 56.808998 129.58215 L 56.831507 128.58215 L 56.898158 127.58215 L 56.947868 126.58215 L 57.021574 125.58215 L 57.052888 124.58215 L 57.12951 123.58215 L 57.167808 122.58215 L 57.241925 121.58215 L 57.345983 120.58215 L 57.415814 119.58215 L 57.521048 118.58215 L 57.576063 117.58215 L 57.699538 116.58215 L 57.770097 115.58215 L 57.885936 114.58215 L 57.936117 113.58215 L 57.971721 112.58215 L 58.063128 111.58215 L 58.116636 110.58215 L 58.204544 109.58215 L 58.273729 108.58215 L 58.320493 107.58215 L 58.392537 106.58215 L 58.442679 105.58215 L 58.460069 104.58215 L 58.487072 103.58215 L 58.506499 102.58215 L 58.525837 101.58215 L 58.564086 100.58215 L 58.580519 99.58215 L 58.588888 98.58215 L 58.593207 97.58215 L 58.599762 96.58215 L 58.597216 95.58215 L 58.591757 94.58215 L 58.575329 93.58215 L 58.543394 92.58215 L 58.505414 91.58215 L 58.47061 90.58215 L 58.407538 89.58215 L 58.386111 88.58215 L 58.335493 87.58215 L 58.310536 86.58215 L 58.254902 85.58215 L 58.223673 84.58215 L 58.173529 83.58215 L 58.141036 82.58215 L 58.060624 81.58215 L 57.991698 80.58215 L 57.876001 79.58215 L 57.800522 78.58215 L 57.684997 77.58215 L 57.605513 76.58215 L 57.497072 75.58215 L 57.457704 74.58215 L 57.354836 73.58215 L 57.255038 72.58215 L 57.209541 71.58215 L 57.175219 70.58215 L 57.123263 69.58215 L 57.083616 68.58215 L 57.048102 67.58215 L 56.980457 66.58215 L 56.941375 65.58215 L 56.890894 64.58215 L 56.841588 63.58215 L 56.790518 62.58215 L 56.746279 61.58215 L 56.724259 60.58215 L 56.708703 59.58215 L 56.666256 58.58215 L 56.651388 57.58215 L 56.62866 56.58215 L 56.608344 55.58215 L 56.602547 54.58215 L 56.600065 53.58215 L 56.603122 52.58215 L 56.614718 51.58215 L 56.631638 50.58215 L 56.663299 49.58215 L 56.677382 48.58215 L 56.730054 47.58215 L 56.779143 46.58215 L 56.833844 44.592945 " + style="fill: none; stroke: #000000; stroke-linecap: round" + id="path16" /> + <path + d="M 54.8 50.192945 L 55.275331 49.312576 L 55.755585 48.434669 L 56.290226 47.583956 L 56.766528 46.704072 L 57.279593 45.842571 L 57.878019 44.731954 L 57.73752 45.642219 L 58.133178 46.562423 L 58.517437 47.488328 L 58.918172 48.405994 L 59.312534 49.326847 L 59.79747 50.49421 " + style="fill: none; stroke: #ffffff; stroke-width: 4; stroke-linecap: round" + id="path17" /> + <path + d="M 54.8 50.192945 L 55.275331 49.312576 L 55.755585 48.434669 L 56.290226 47.583956 L 56.766528 46.704072 L 57.279593 45.842571 L 57.878019 44.731954 L 57.73752 45.642219 L 58.133178 46.562423 L 58.517437 47.488328 L 58.918172 48.405994 L 59.312534 49.326847 L 59.79747 50.49421 " + style="fill: none; stroke: #000000; stroke-linecap: round" + id="path18" /> + </g> + </g> + </g> + <defs + id="defs18"> + <clipPath + id="p53efc7421d"> + <rect + x="57.6" + y="41.472" + width="357.12" + height="266.112" + id="rect18" /> + </clipPath> + </defs> + <path + style="fill:#ffffff;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-opacity:0.18525;fill-opacity:1" + d="m 402.11605,300.06616 2.16807,0.15101 -0.0108,-1.35908 -2.54559,0.35595 z" + id="path19" /> + <path + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-opacity:0.18525" + d="m 404.52142,306.22518 2.04941,0.0971 -0.1618,0.98156 -1.77975,-0.31281 z" + id="path20" /> + <path + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-opacity:0.18525" + d="M 63.984775,40.686206 63.812194,51.041125 69.766273,51.170562 69.075944,39.69386 Z" + id="path21" /> + <path + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-opacity:0.18525" + d="m 56.105329,51.747633 0.04315,-1.876829 h 1.008527 l -0.02157,0.328984 -0.711901,1.661102 z" + id="path22" /> +</svg> diff --git a/getting-started/generative-ai.rst b/getting-started/generative-ai.rst index 90fe020f3f..e4aa3e7586 100644 --- a/getting-started/generative-ai.rst +++ b/getting-started/generative-ai.rst @@ -4,10 +4,10 @@ Generative AI ============= -Generative AI has evolved rapidly over the past decade and will continue in the future. -Using generative AI and large language models (LLMs) can be helpful tools for contributors. -Their overuse can also be problematic, such as generation of incorrect code, inaccurate documentation, and unneeded code churn. -Discretion, good judgement, and critical thinking **must** be used when opening issues and pull requests. +Generative AI tools have evolved rapidly, and their suggested results can be helpful. As with using any tool, the resulting contribution is +the responsibility of the contributor. We value good code, concise accurate documentation, and avoiding unneeded code +churn. Discretion, good judgment, and critical thinking are the foundation of all good contributions, regardless of the +tools used in their creation. Acceptable uses =============== @@ -24,3 +24,17 @@ Unacceptable uses Maintainers may close issues and PRs that are not useful or productive, including those that are fully generated by AI. If a contributor repeatedly opens unproductive issues or PRs, they may be blocked. + +Considerations for success +========================== +- While AI assisted tools such as autocompletion can enhance productivity, they sometimes rewrite entire code blocks instead of making small, focused edits. + This can make it more difficult to review changes and to fully understand both the original intent of the code and the rationale behind the new modifications. + Maintaining consistency with the original code helps preserve clarity, traceability, and meaningful reviews and also helps us avoid unnecessary code churn. +- Sometimes AI assisted tools make failing unit tests pass by altering or bypassing the tests rather than addressing the underlying problem in the code. + Such changes do not represent a real fix. Authors must review the work done by AI tooling in detail to ensure it actually makes sense before proposing it as a PR. +- Keep the following principles for the quality of your contributions in mind whether you use generative AI or not: + + - Consider whether the change is necessary + - Make minimal, focused changes + - Follow existing coding style and patterns + - Write tests that exercise the change diff --git a/getting-started/getting-help.rst b/getting-started/getting-help.rst index 4e993a1e9e..fc289fd449 100644 --- a/getting-started/getting-help.rst +++ b/getting-started/getting-help.rst @@ -5,7 +5,7 @@ Where to get help ================= If you are working on Python it is very possible you will come across an issue -where you need some assistance to solve it (this happens to core developers +where you need some assistance to solve it (this happens to the core team all the time). Should you require help, there are a :ref:`variety of options available @@ -37,31 +37,12 @@ Those particularly relevant for help contributing to Python itself include: .. _Ideas: https://discuss.python.org/c/ideas/6 -.. _help-mailing-lists: - -Mailing lists -------------- - -Further options for seeking assistance include the -`python-ideas`_ and `python-dev`_ mailing lists, -which correspond to the `Ideas`_ and `Core Development`_ -:ref:`help-discourse` categories, respectively. -The Discourse categories are generally more active -and are the preferred venue for new discussions, -but the mailing lists are still monitored and responded to. -These mailing lists are for questions involving the -development *of* Python, **not** for development *with* Python. - -.. _python-ideas: https://mail.python.org/mailman3/lists/python-ideas.python.org -.. _python-dev: https://mail.python.org/mailman3/lists/python-dev.python.org/ - - Ask #python-dev --------------- If you are comfortable with IRC you can try asking on ``#python-dev`` (on the `Libera.Chat`_ network). Typically there are a number of experienced -developers, ranging from triagers to core developers, who can answer +contributors, ranging from triagers to the core team, who can answer questions about developing for Python. As with the mailing lists, ``#python-dev`` is for questions involving the development *of* Python whereas ``#python`` is for questions concerning development *with* Python. @@ -79,7 +60,7 @@ Core mentorship If you are interested in improving Python and contributing to its development, but don’t yet feel entirely comfortable with the public channels mentioned above, `Python Mentors`_ are here to help you. Python is fortunate to have a -community of volunteer core developers willing to mentor anyone wishing to +community of volunteer core team members willing to mentor anyone wishing to contribute code, work on bug fixes or improve documentation. Everyone is welcomed and encouraged to contribute. diff --git a/getting-started/git-boot-camp.rst b/getting-started/git-boot-camp.rst index 87177840cb..6808e99b47 100644 --- a/getting-started/git-boot-camp.rst +++ b/getting-started/git-boot-camp.rst @@ -4,13 +4,7 @@ Git bootcamp and cheat sheet ============================ -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst .. highlight:: console @@ -33,7 +27,7 @@ relevant to CPython's workflow. .. note:: Setting up Git aliases for common tasks can be useful to you. You can get more information about that in - `Git documentation <https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases>`_ + `Git documentation <https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases>`__ .. _fork-cpython: @@ -280,7 +274,7 @@ Compare to the ``main`` branch:: $ git diff main Exclude generated files from diff using an ``attr`` -`pathspec <https://git-scm.com/docs/gitglossary#def_pathspec>`_ (note the +`pathspec <https://git-scm.com/docs/gitglossary#def_pathspec>`__ (note the single quotes):: $ git diff main ':(attr:!generated)' @@ -289,7 +283,7 @@ Exclude generated files from diff by default:: $ git config diff.generated.binary true -The ``generated`` `attribute <https://git-scm.com/docs/gitattributes>`_ is +The ``generated`` `attribute <https://git-scm.com/docs/gitattributes>`__ is defined in :cpy-file:`.gitattributes`, found in the repository root. .. _push-changes: @@ -389,8 +383,8 @@ you run ``git merge upstream/main``. When it happens, you need to resolve conflict. See these articles about resolving conflicts: -- `About merge conflicts <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts>`_ -- `Resolving a merge conflict using the command line <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line>`_ +- `About merge conflicts <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts>`__ +- `Resolving a merge conflict using the command line <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line>`__ .. _git_from_patch: @@ -443,8 +437,8 @@ Scenario: - A contributor made a pull request to CPython. - Before merging it, you want to be able to test their changes locally. -If you've got `GitHub CLI <https://cli.github.com>`_ or -`hub <https://hub.github.com>`_ installed, you can do:: +If you've got `GitHub CLI <https://cli.github.com>`__ or +`hub <https://hub.github.com>`__ installed, you can do:: $ gh co <pr_number> # GitHub CLI $ hub pr checkout <pr_number> # hub @@ -523,7 +517,7 @@ The bad example contains bullet points that are a direct effect of the PR life cycle, while being irrelevant to the final change. .. note:: - `How to Write a Git Commit Message <https://cbea.ms/git-commit/>`_ + `How to Write a Git Commit Message <https://cbea.ms/git-commit/>`__ is a nice article describing how to write a good commit message. Finally, press the :guilabel:`Confirm squash and merge` button. @@ -557,7 +551,7 @@ after it has been accepted and merged into ``main``. It is usually indicated by the label ``needs backport to X.Y`` on the pull request itself. Use the utility script -`cherry_picker.py <https://github.com/python/cherry-picker>`_ +`cherry_picker.py <https://github.com/python/cherry-picker>`__ to backport the commit. The commit hash for backporting is the squashed commit that was merged to @@ -611,7 +605,7 @@ When a pull request submitter has enabled the `Allow edits from maintainers`_ option, Python Core Developers may decide to make any remaining edits needed prior to merging themselves, rather than asking the submitter to do them. This can be particularly appropriate when the remaining changes are bookkeeping -items like updating ``Misc/ACKS``. +items like updating a news entry. .. _Allow edits from maintainers: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork @@ -649,12 +643,12 @@ To edit an open pull request that targets ``main``: GitHub CLI ---------- -`GitHub CLI <https://cli.github.com>`_ is a command-line +`GitHub CLI <https://cli.github.com>`__ is a command-line interface that allows you to create, update, and check GitHub issues and pull requests. You can install GitHub CLI `by following these instructions -<https://github.com/cli/cli#installation>`_. After installing, +<https://github.com/cli/cli#installation>`__. After installing, you need to authenticate:: $ gh auth login @@ -740,6 +734,6 @@ Change into a directory to work from that branch. For example:: .. seealso:: - * `Git Reference Manual <https://git-scm.com/docs/git-worktree>`_ + * `Git Reference Manual <https://git-scm.com/docs/git-worktree>`__ * `"Experiment on your code freely with Git worktree" - <https://opensource.com/article/21/4/git-worktree>`_ + <https://opensource.com/article/21/4/git-worktree>`__ diff --git a/getting-started/pull-request-lifecycle.rst b/getting-started/pull-request-lifecycle.rst index 59242f13f0..c1e471c17d 100644 --- a/getting-started/pull-request-lifecycle.rst +++ b/getting-started/pull-request-lifecycle.rst @@ -54,10 +54,13 @@ Here is a quick overview of how you can contribute to CPython: .. [*] If an issue is trivial (for example, typo fixes), or if an issue already exists, you can skip this step. -.. note:: - In order to keep the commit history intact, please avoid squashing or amending - history and then force-pushing to the PR. Reviewers often want to look at - individual commits. +Don't force-push +---------------- + +In order to keep the commit history intact, please avoid squashing or amending +history and then force-pushing to the PR. Reviewers often want to look at +individual commits. +When the PR is merged, everything will be squashed into a single commit. .. _Clear communication: https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution .. _Open Source: https://opensource.guide/ @@ -131,7 +134,7 @@ You should have already :ref:`set up your system <setup>`, git commit -m '<message>' git push origin <branch-name> - * If a core developer reviewing your PR pushed one or more commits to your + * If a core team member reviewing your PR pushed one or more commits to your PR branch, then after checking out your branch and before editing, run:: git pull origin <branch-name> # pull = fetch + merge @@ -180,7 +183,7 @@ resolved as follows: When running the final command, Git may open an editor for writing a commit message. It is usually okay to leave that as-is and close the editor. -See `the merge command's documentation <https://git-scm.com/docs/git-merge>`_ +See `the merge command's documentation <https://git-scm.com/docs/git-merge>`__ for a detailed technical explanation. @@ -204,7 +207,7 @@ should do to help ensure that your pull request is accepted. #. **Make sure to follow Python's style guidelines.** For Python code you should follow :PEP:`8`, and for C code you should follow :PEP:`7`. If you have - one or two discrepancies those can be fixed by the core developer who merges + one or two discrepancies those can be fixed by the core team member who merges your pull request. But if you have systematic deviations from the style guides your pull request will be put on hold until you fix the formatting issues. @@ -237,6 +240,105 @@ should do to help ensure that your pull request is accepted. #. Proper :ref:`documentation <documenting>` additions/changes should be included. +.. _news-entry: +.. _what-s-new-and-news-entries: + +Updating NEWS and What's New in Python +====================================== + +Changes that require NEWS entries +--------------------------------- + +Most changes made to the codebase deserve an entry in :cpy-file:`Misc/NEWS.d`, +except for the following: + +* documentation changes +* test changes +* strictly internal changes with no user-visible effects +* changes that already have a ``NEWS`` entry +* reverts that have not yet been included in any formal release + (including alpha and beta releases) + +For the last two, note the following: + +#. **If a change is reverted prior to release**, then the corresponding + entry is simply removed. Otherwise, a new entry must be added noting + that the change has been reverted (for example, when a feature is released in + an alpha and then cut prior to the first beta). + +#. **If a change is a fix (or other adjustment) to an earlier unreleased + change and the original** ``NEWS`` **entry remains valid**, then no additional + entry is needed. + +Changes that require "What's New in Python" entries +--------------------------------------------------- + +If a change is particularly interesting for end users (for example, new features, +significant improvements, or backwards-incompatible changes), add an entry in +the "What's New in Python" document (in :cpy-file:`Doc/whatsnew/`, the 3.X.rst +file where X is the current Python version) in addition to the ``NEWS`` entry. + +In most cases, it is sufficient to reuse the wording from the ``NEWS`` entry +in the "What's New in Python" entry. + +.. note:: + + A change that needs an entry in "What's New in Python" + is very likely not suitable for inclusion in a maintenance release. + +How to add a NEWS entry +----------------------- + +``NEWS`` entries go into the ``Misc/NEWS.d`` directory as individual files. The +``NEWS`` entry can be created by using `blurb-it <https://blurb-it.herokuapp.com/>`_, +or the :pypi:`blurb` tool and its ``blurb add`` command. + +If you are unable to use the tool, then you can create the ``NEWS`` entry file +manually. The ``Misc/NEWS.d`` directory contains a sub-directory named +``next``, which contains various sub-directories representing classifications +for what was affected (for example, ``Misc/NEWS.d/next/Library`` for changes relating +to the standard library). The file name itself should be in the format +``<datetime>.gh-issue-<issue-number>.<nonce>.rst``: + +* ``<datetime>`` is today's date joined with a hyphen (``-``) to your current + local time, in the ``YYYY-MM-DD-hh-mm-ss`` format (for example, ``2017-05-27-16-46-23``). +* ``<issue-number>`` is the issue number the change is for (for example, ``12345`` + for ``gh-issue-12345``). +* ``<nonce>`` is a unique string to guarantee that the file name is + unique across branches (for example, ``Yl4gI2``). It is typically six characters + long, but it can be any length of letters and numbers. Its uniqueness + can be satisfied by typing random characters on your keyboard. + +As a result, a file name can look something like +``Misc/NEWS.d/next/Library/2017-05-27-16-46-23.gh-issue-12345.Yl4gI2.rst``. + +How to write a NEWS entry +------------------------- + +All ``NEWS`` entries end up being part of the changelog. +The changelog contains *a lot* of entries, +and its intended audience is mainly users, not core devs and contributors. +Take this into consideration when wording your ``NEWS`` entry. +Describe the user-visible effects of your change succinctly and accurately; +avoid long technical elaborations, digressions, and do not expect or require +the reader to have read the actual diff for the change. + +The contents of a ``NEWS`` file should be valid reStructuredText. An 80 character +column width should be used. There is no indentation or leading marker in the +file (for example, ``-``). There is also no need to start the entry with the issue +number since it is part of the file name. You can use +:ref:`inline markups <rest-inline-markup>` too. Here is an example of a ``NEWS`` +entry: + +.. code-block:: rst + + Fix warning message when :func:`os.chdir` fails inside + :func:`test.support.temp_cwd`. Contributed by Chris Jerdonek. + +The inline Sphinx roles like :rst:role:`:func: <py:func>` can be used help readers +find more information. You can build HTML and verify that the +link target is appropriate by using :ref:`make html <building-using-make>`. + Copyrights ========== @@ -277,23 +379,16 @@ On *Windows* (after any successful build): The automated checklist runs through: -* Are there any whitespace problems in Python files? - (using :cpy-file:`Tools/patchcheck/reindent.py`) -* Are there any whitespace problems in C files? -* Are there any whitespace problems in the documentation? * Has the documentation been updated? * Has the test suite been updated? * Has an entry under ``Misc/NEWS.d/next`` been added? - (using `blurb-it <https://blurb-it.herokuapp.com/>`_, + (using `blurb-it <https://blurb-it.herokuapp.com/>`__, or the :pypi:`blurb` tool) -* Has ``Misc/ACKS`` been updated? * Has ``configure`` been regenerated, if necessary? * Has ``pyconfig.h.in`` been regenerated, if necessary? -The automated checks don't actually *answer* all of these -questions. Aside from the whitespace checks, the tool is -a memory aid for the various elements that can go into -making a complete pull request. +This will help you remember things that you need +to check before submitting a complete pull request. .. _good-commits: @@ -324,7 +419,7 @@ Furthermore, the first line should not end in a period. If this is not enough detail for a commit, a new paragraph(s) can be added to explain in proper depth what has happened (detail should be good enough -that a core developer reading the commit message understands the +that a core team member reading the commit message understands the justification for the change). Check :ref:`the Git bootcamp <accepting-and-merging-a-pr>` for further @@ -332,7 +427,7 @@ instructions on how the commit message should look like when merging a pull request. .. note:: - `How to Write a Git Commit Message <https://cbea.ms/git-commit/>`_ + `How to Write a Git Commit Message <https://cbea.ms/git-commit/>`__ is a nice article that describes how to write a good commit message. @@ -354,20 +449,54 @@ Here are the steps needed in order to sign the CLA: 1. Create a change and submit it as a pull request. -2. When ``cpython-cla-bot`` comments on your pull request that commit +2. When ``python-cla-bot`` comments on your pull request that commit authors are required to sign a Contributor License Agreement, click on the button in the comment to sign it. It's enough to log in through GitHub. The process is automatic. -3. After signing, the comment by ``cpython-cla-bot`` will update to +3. After signing, the comment by ``python-cla-bot`` will update to indicate that "all commit authors signed the Contributor License - Agreement. + Agreement". .. _PSF license: https://docs.python.org/dev/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python .. _contributor agreement: https://www.python.org/psf/contrib/ .. _contributor form: https://www.python.org/psf/contrib/contrib-form/ .. _Python Software Foundation: https://www.python.org/psf-landing/ +Why do I need to sign the CLA again? +------------------------------------ + +Sometimes the CLA bot asks you to sign the CLA for a backport PR, +when you've already signed it for the original PR. +This is because you need to sign the CLA for all the email addresses you commit +with. + +This can happen when you've `configured your Git client +<https://docs.github.com/en/account-and-profile/how-tos/email-preferences/setting-your-commit-email-address>`__ +with one email address, and signed the CLA with this, but have +`configured your GitHub account <https://github.com/settings/emails>`__ +with another primary email +(often this is the private ``id+username@users.noreply.github.com`` address). + +1. In the original PR, the CLA bot verifies all the emails in the commits have + signed the CLA. + +2. We then squash merge the PR, which creates a single new commit using the + author's primary email. This can be different from the one you originally + committed with. + +3. Backports often only have this new single commit. + The CLA bot then checks if the primary email has signed the CLA. + +4. The solution is to click the :guilabel:`CLA not signed -- click to sign` + button in the backport PR. + +.. tip:: Run ``git config user.email`` to see your Git client config, + and append ``.patch`` to a PR URL to see the emails used for its commits: + + * https://github.com/python/cpython/pull/1 + * https://github.com/python/cpython/pull/1.patch + Submitting ========== @@ -386,7 +515,7 @@ This will get your changes up to GitHub. Now you want to `create a pull request from your fork -<https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork>`_. +<https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork>`__. If this is a pull request in response to a pre-existing issue on the `issue tracker`_, please make sure to reference the issue number using ``gh-NNNNN:`` prefix in the pull request title and ``#NNNNN`` in the description. @@ -421,7 +550,7 @@ existing patch. In this case, both parties should sign the :ref:`CLA <cla>`. When creating a pull request based on another person's patch, provide attribution to the original patch author by adding "Co-authored-by: Author Name <email_address> ." to the pull request description and commit message. -See `the GitHub article <https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors>`_ +See `the GitHub article <https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors>`__ on how to properly add the co-author info. See also :ref:`Applying a Patch to Git <git_from_patch>`. @@ -447,7 +576,7 @@ to ask for someone to review your pull request. When someone does manage to find the time to look at your pull request they will most likely make comments about how it can be improved -(don't worry, even core developers of Python have their pull requests sent +(don't worry, even core team members of Python have their pull requests sent back to them for changes). It is then expected that you update your pull request to address these comments, and the review process will thus iterate until a satisfactory solution has emerged. @@ -514,11 +643,13 @@ Instead of simply "approving" the pull request, leave comments. For example: #. Look at any failures in CI on the current PR. See :ref:`"Keeping CI green" <keeping-ci-green>` below for simple things you can do to help move the PR forward. -Dismissing review from another core developer ---------------------------------------------- +.. _dismissing-review-from-another-core-developer: + +Dismissing review from another core team member +----------------------------------------------- -A core developer can dismiss another core developer's review if they confirmed -that the requested changes have been made. When a core developer has assigned +A core team member can dismiss another team member's review if they confirmed +that the requested changes have been made. When a core team member has assigned the PR to themselves, then it is a sign that they are actively looking after the PR, and their review should not be dismissed. @@ -545,7 +676,7 @@ affects other PRs. If you still don't see where the failure originates from, check for a "This branch is out-of-date with the base branch" sign next to the -list of executed checks. Clicking "Update branch" next to this message +list of executed checks. Clicking :guilabel:`Update branch` next to this message will merge in the latest changes from the base branch into the PR. If this still doesn't help with the failure on the PR, you can try @@ -589,17 +720,15 @@ Python is tricky and we simply cannot accept everyone's contributions. But if your pull request is merged it will then go into Python's :abbr:`VCS (version control system)` to be released with the next feature release of Python. It may also be backported to older -versions of Python as a bugfix if the core developer doing the merge believes +versions of Python as a bugfix if the core team member doing the merge believes it is warranted. Crediting ========= -Non-trivial contributions are credited in the ``Misc/ACKS`` file (and, most -often, in a contribution's news entry as well). You may be -asked to make these edits on the behalf of the core developer who -accepts your pull request. +Non-trivial contributions are often credited in What's New in Python +and a contributions's news entry as well. .. _issue tracker: https://github.com/python/cpython/issues .. _Core Development Discourse category: https://discuss.python.org/c/core-dev/23 diff --git a/getting-started/setup-building.rst b/getting-started/setup-building.rst index 03b2777b8e..2204d6f943 100644 --- a/getting-started/setup-building.rst +++ b/getting-started/setup-building.rst @@ -5,13 +5,7 @@ Setup and building ================== -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst .. highlight:: console @@ -20,9 +14,9 @@ compiled version of the CPython interpreter (CPython is the version of Python available from https://www.python.org/). It also gives an overview of the directory structure of the CPython source code. -Alternatively, if you have `Docker <https://www.docker.com/>`_ installed you +Alternatively, if you have `Docker <https://www.docker.com/>`__ installed you might want to use `our official images -<https://gitlab.com/python-devs/ci-images/blob/main/README.md>`_. These +<https://gitlab.com/python-devs/ci-images/blob/main/README.md>`__. These contain the latest releases of several Python versions, along with Git head, and are provided for development and testing purposes only. @@ -36,34 +30,39 @@ and are provided for development and testing purposes only. Install Git =========== -CPython is developed using `Git <https://git-scm.com>`_ for version control. The Git +.. c_install_git_start + +CPython is developed using `Git <https://git-scm.com>`__ for version control. The Git command line program is named ``git``; this is also used to refer to Git itself. Git is easily available for all common operating systems. - **Install** As the CPython repo is hosted on GitHub, please refer to either the - `GitHub setup instructions <https://docs.github.com/en/get-started/getting-started-with-git/set-up-git>`_ - or the `Git project instructions <https://git-scm.com>`_ for step-by-step + `GitHub setup instructions <https://docs.github.com/en/get-started/getting-started-with-git/set-up-git>`__ + or the `Git project instructions <https://git-scm.com>`__ for step-by-step installation directions. You may also want to consider a graphical client - such as `TortoiseGit <https://tortoisegit.org/>`_ or - `GitHub Desktop <https://github.com/apps/desktop>`_. + such as `TortoiseGit <https://tortoisegit.org/>`__ or + `GitHub Desktop <https://github.com/apps/desktop>`__. - **Configure** Configure :ref:`your name and email <set-up-name-email>` and create - `an SSH key <https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account>`_ + `an SSH key <https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account>`__ as this will allow you to interact with GitHub without typing a username and password each time you execute a command, such as ``git pull``, ``git push``, or ``git fetch``. On Windows, you should also :ref:`enable autocrlf <autocrlf>`. +.. c_install_git_end .. _checkout: Get the source code =================== +.. c_get_source_code_start + The CPython repo is hosted on GitHub. To get a copy of the source code you should :ref:`fork the Python repository on GitHub <fork-cpython>`, :ref:`create a local clone of your personal fork, and configure the remotes <clone-your-fork>`. @@ -136,18 +135,22 @@ Install pre-commit as a Git hook -------------------------------- To make sure your code is linted correctly, we recommend setting up -`pre-commit <https://pre-commit.com#installation>`_ as a Git hook:: +`pre-commit <https://pre-commit.com#installation>`__ as a Git hook:: $ pre-commit install --allow-missing-config pre-commit installed at .git/hooks/pre-commit Now pre-commit will run automatically on ``git commit``. +.. c_get_source_code_end + .. _compiling: Compile and build ================= +.. c_compile_and_build_start + CPython provides several compilation flags which help with debugging various things. While all of the known flags can be found in the ``Misc/SpecialBuilds.txt`` file, the most critical one is the ``Py_DEBUG`` flag @@ -161,7 +164,7 @@ working only on pure Python code the pydebug build provides several useful checks that one should not skip. .. seealso:: The effects of various configure and build flags are documented in - the `Python configure docs <https://docs.python.org/dev/using/configure.html>`_. + the `Python configure docs <https://docs.python.org/dev/using/configure.html>`__. .. _unix-compiling: @@ -194,14 +197,13 @@ do to get a pydebug build of CPython. Once ``configure`` is done, you can then compile CPython with:: - $ make -s -j2 + $ make -s -j $(nproc) This will build CPython with only warnings and errors being printed to -stderr and utilize up to 2 CPU cores. If you are using a multi-core machine -with more than 2 cores (or a single-core machine), you can adjust the number -passed into the ``-j`` flag to match the number of cores you have (or if your -version of Make supports it, you can use ``-j`` without a number and Make -will not limit the number of steps that can run simultaneously.). +stderr. The ``-j`` argument means that :program:`make` will concurrently run +tasks, limiting the number of parallel jobs to the number of CPU cores in your +computer. You can adjust the number passed to the ``-j`` flag to change +the limit on parallel jobs, which can trade RAM usage versus compilation time. At the end of the build you should see a success message, followed by a list of extension modules that haven't been built because their @@ -377,63 +379,98 @@ compiler just like building for :ref:`Unix <unix-compiling>` as well as: 1. A C compiler that can target WebAssembly (for example, `WASI SDK`_) 2. A WASI host/runtime (for example, Wasmtime_) +3. A system install of Python 3.11 or newer to run the build scripts -All of this is provided in the :ref:`devcontainer <using-codespaces>`. You can -also use what's installed in the container as a reference of what versions of -these tools are known to work. +All of this is provided in the WASI :ref:`dev container <using-a-container>` +(which you can select as an alternative container when using a +:ref:`codespace <codespaces-whats-codespaces>`). You can also use what's +installed in the container as a reference of what versions of these tools are +known to work. .. note:: - CPython has only been verified with the above tools for WASI. Using - other compilers, hosts, or WASI versions *should* work, but the above tools - and their versions specified in the container are tested via a - :ref:`buildbot <buildbots>`. + CPython has only been verified with the certain tools for WASI. Using + other compilers, hosts, or WASI versions *should* work, but the tools + and their versions specified in the container and build scripts are + tested via a :ref:`buildbot <buildbots>`. Building for WASI requires doing a cross-build where you have a *build* Python to help produce a WASI build of CPython (technically it's a "host x host" cross-build because the build Python is also the target Python while the host build is the WASI build). This means you effectively build CPython twice: once to have a version of Python for the build system to use and another that's the -build you ultimately care about (that is, the build Python is not meant for use by -you directly, only the build system). +build you ultimately care about (that is, the build Python is not meant for use +by you directly, only the build system). -The easiest way to get a debug build of CPython for WASI is to use the -``Tools/wasm/wasi.py build`` command (which should be run w/ a recent version of -Python you have installed on your machine): +The easiest way to get a debug build of CPython for WASI is to run the +following command with Python 3.11 or newer: -.. code-block:: shell +.. tab:: Python 3.15+ + + .. code-block:: shell + + python Platforms/WASI build --quiet -- --config-cache --with-pydebug + +.. tab:: Python 3.14 - $ python3 Tools/wasm/wasi.py build --quiet -- --config-cache --with-pydebug + .. code-block:: shell + + python Tools/wasm/wasi build --quiet -- --config-cache --with-pydebug + +.. tab:: Python 3.13 + + .. code-block:: shell + + python Tools/wasm/wasi.py build --quiet -- --config-cache --with-pydebug That single command will configure and build both the build Python and the -WASI build in ``cross-build/build`` and ``cross-build/wasm32-wasi``, -respectively. +WASI build in the ``cross-build/`` directory. You can also do each configuration and build step separately; the command above is a convenience wrapper around the following commands: -.. code-block:: shell +.. tab:: Python 3.15+ + + .. code-block:: shell + + $ python Platforms/WASI configure-build-python --quiet -- --config-cache --with-pydebug + $ python Platforms/WASI make-build-python --quiet + $ python Platforms/WASI configure-host --quiet -- --config-cache + $ python Platforms/WASI make-host --quiet + +.. tab:: Python 3.14 + + .. code-block:: shell - $ python Tools/wasm/wasi.py configure-build-python --quiet -- --config-cache --with-pydebug - $ python Tools/wasm/wasi.py make-build-python --quiet - $ python Tools/wasm/wasi.py configure-host --quiet -- --config-cache - $ python Tools/wasm/wasi.py make-host --quiet + $ python Tools/wasm/wasi configure-build-python --quiet -- --config-cache --with-pydebug + $ python Tools/wasm/wasi make-build-python --quiet + $ python Tools/wasm/wasi configure-host --quiet -- --config-cache + $ python Tools/wasm/wasi make-host --quiet + +.. tab:: Python 3.13 + + .. code-block:: shell + + $ python Tools/wasm/wasi.py configure-build-python --quiet -- --config-cache --with-pydebug + $ python Tools/wasm/wasi.py make-build-python --quiet + $ python Tools/wasm/wasi.py configure-host --quiet -- --config-cache + $ python Tools/wasm/wasi.py make-host --quiet .. note:: The ``configure-host`` command infers the use of ``--with-pydebug`` from the build Python. -Running the separate commands after ``wasi.py build`` is useful if you, for example, only want to -run the ``make-host`` step after making code changes. +Running the separate commands after ``build`` is useful if you, for example, +only want to run the ``make-host`` step after making code changes. Once everything is complete, there will be a -``cross-build/wasm32-wasi/python.sh`` helper file which you can use to run the +``cross-build/wasm32-wasip1/python.sh`` helper file which you can use to run the ``python.wasm`` file (see the output from the ``configure-host`` subcommand): .. code-block:: shell - $ cross-build/wasm32-wasi/python.sh --version + cross-build/wasm32-wasip1/python.sh --version You can also use ``Makefile`` targets and they will work as expected thanks to the ``HOSTRUNNER`` environment variable having been set to a similar value as @@ -441,7 +478,7 @@ used in ``python.sh``: .. code-block:: shell - $ make -C cross-build/wasm32-wasi test + make -C cross-build/wasm32-wasip1 test .. note:: @@ -458,6 +495,114 @@ used in ``python.sh``: .. _wasmtime: https://wasmtime.dev .. _WebAssembly: https://webassembly.org + +Emscripten +---------- + +Emscripten_ is a complete open-source compiler toolchain. It compiles C/C++ code +into WebAssembly_/JavaScript executables, for use in JavaScript runtimes, +including browsers and Node.js. + +.. note:: + + The instructions below assume a Unix-based OS due to cross-compilation for + CPython being designed for ``./configure`` / ``make``. + +To build for Emscripten, you will need to cross-compile CPython. This requires a +C compiler just like building for :ref:`Unix <unix-compiling>` as well as: + +* The Emscripten compiler +* Node.js + +The simplest way to install the Emscripten compiler is: + +.. code-block:: sh + + # Install Emscripten + git clone https://github.com/emscripten-core/emsdk + ./emsdk/emsdk install 4.0.12 + ./emsdk/emsdk activate 4.0.12 + source ./emsdk/emsdk_env.sh + +Updating the Emscripten compiler version can cause breakages. For the best +compatibility, use the appropriate Emscripten version based on the version of +CPython you're building: + +* For building CPython 3.14, use ``emsdk`` version ``4.0.12``. +* For building the main branch of the CPython repository, you may wish to use + ``latest`` instead of a specific version. + +It is possible (but not necessary) to enable ``ccache`` for Emscripten builds +by setting the ``EM_COMPILER_WRAPPER`` environment, but this step will only +take effect if it is done **after** ``emsdk_env.sh`` is sourced (otherwise, the +sourced script removes the environment variable): + +.. code-block:: sh + + export EM_COMPILER_WRAPPER=ccache + +Building for Emscripten requires doing a cross-build where you have a *build* +Python to help produce an Emscripten build of CPython. This means you build +CPython twice: once to have a version of Python for the build system to use and +another that's the build you ultimately care about (that is, the build Python is +not meant for use by you directly, only the build system). + +The easiest way to get a debug build of CPython for Emscripten is to use the +``Tools/wasm/emscripten build`` command, which should be run with a recent +version of Python (3.13 or newer) already installed on your machine: + +.. code-block:: shell + + python3 Tools/wasm/emscripten build --quiet -- --config-cache --with-pydebug + +That single command will configure and build both the build Python and the +Emscripten build in ``cross-build/build`` and +``cross-build/wasm32-emscripten/build/python/``, respectively. + +You can also do each configuration and build step separately; the command above +is a convenience wrapper around the following commands: + +.. code-block:: shell + + python Tools/wasm/emscripten configure-build-python --quiet -- --config-cache --with-pydebug + python Tools/wasm/emscripten make-build-python --quiet + python Tools/wasm/emscripten make-libffi --quiet + python Tools/wasm/emscripten make-mpdec --quiet + python Tools/wasm/emscripten configure-host --quiet -- --config-cache + python Tools/wasm/emscripten make-host --quiet + +.. note:: + + The ``configure-host`` command infers the use of ``--with-pydebug`` from the + build Python. + +Running the separate commands after ``emscripten build`` is useful if you, for +example, only want to run the ``make-host`` step after making code changes. + +Once everything is complete, there will be a +``cross-build/wasm32-emscripten/build/python/python.sh`` helper file which you +can use to run the ``python.mjs`` file: + +.. code-block:: shell + + cross-build/wasm32-emscripten/build/python/python.sh --version + +You can also use ``Makefile`` targets and they will work as expected thanks to +the ``HOSTRUNNER`` environment variable having been set to a similar value as +used in ``python.sh``: + +.. code-block:: shell + + make -C cross-build/wasm32-emscripten/build/python/ test + +Additional instructions for running the resulting builds (through Node.js and/or +through web browsers) are available in the CPython repository at +:cpy-file:`Tools/wasm/README.md`. + +.. _Emscripten: https://emscripten.org/ +.. _WebAssembly: https://webassembly.org + + Android ------- @@ -606,6 +751,8 @@ single test, or a subset of tests. See the `iOS README <https://github.com/python/cpython/blob/main/iOS/README.rst#debugging-test-failures>`__ for details. +.. c_compile_and_build_end + .. _build-dependencies: .. _deps-on-linux: .. _macOS and OS X: @@ -614,6 +761,8 @@ for details. Install dependencies ==================== +.. c_install_dependencies_start + This section explains how to install libraries which are needed to compile some of CPython's modules (for example, ``zlib``). @@ -636,9 +785,9 @@ some of CPython's modules (for example, ``zlib``). $ sudo dnf install \ gcc gcc-c++ gdb lzma glibc-devel libstdc++-devel openssl-devel \ - readline-devel zlib-devel libffi-devel bzip2-devel xz-devel \ - sqlite sqlite-devel sqlite-libs libuuid-devel gdbm-libs perf \ - expat expat-devel mpdecimal python3-pip + readline-devel zlib-devel libzstd-devel libffi-devel bzip2-devel \ + xz-devel sqlite sqlite-devel sqlite-libs libuuid-devel gdbm-libs \ + perf expat expat-devel mpdecimal python3-pip On **Debian**, **Ubuntu**, and other ``apt``-based systems, try to get the @@ -674,10 +823,15 @@ some of CPython's modules (for example, ``zlib``). $ sudo apt-get install build-essential gdb lcov pkg-config \ libbz2-dev libffi-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \ libncurses5-dev libreadline6-dev libsqlite3-dev libssl-dev \ - lzma lzma-dev tk-dev uuid-dev zlib1g-dev libmpdec-dev + lzma lzma-dev tk-dev uuid-dev zlib1g-dev libmpdec-dev libzstd-dev \ + inetutils-inetd - Note that Debian 12 and Ubuntu 24.04 do not have the ``libmpdec-dev`` package. You can safely - remove it from the install list above and the Python build will use a bundled version. + Note that Debian 12 and Ubuntu 24.04 do not have the ``libmpdec-dev`` + package. You can safely remove it from the install list above and the + Python build will use a bundled version. But we recommend using the system + `libmpdec <https://www.bytereef.org/mpdecimal/doc/libmpdec/>`__ library. + Either build it from sources or install this package from + https://deb.sury.org. .. tab:: macOS @@ -709,30 +863,20 @@ some of CPython's modules (for example, ``zlib``). For **Homebrew**, install dependencies using ``brew``:: - $ brew install pkg-config openssl@3 xz gdbm tcl-tk mpdecimal - - .. tab:: Python 3.13+ - - For Python 3.13 and newer:: - - $ GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ - GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ - ./configure --with-pydebug \ - --with-system-libmpdec \ - --with-openssl="$(brew --prefix openssl@3)" + $ brew install pkg-config openssl@3 xz gdbm tcl-tk mpdecimal zstd - .. tab:: Python 3.11-3.12 + .. tab:: Python 3.11+ - For Python 3.11 and 3.12:: + For Python 3.11 and newer:: $ GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ ./configure --with-pydebug \ --with-openssl="$(brew --prefix openssl@3)" - .. tab:: Python 3.9-3.10 + .. tab:: Python 3.10 - For Python 3.9 and 3.10:: + For Python 3.10:: $ CPPFLAGS="-I$(brew --prefix gdbm)/include -I$(brew --prefix xz)/include" \ LDFLAGS="-L$(brew --prefix gdbm)/lib -L$(brew --prefix xz)/lib" \ @@ -743,14 +887,14 @@ some of CPython's modules (for example, ``zlib``). --with-dbmliborder=gdbm:ndbm (``--with-dbmliborder`` is a workaround for a Homebrew-specific change - to ``gdbm``; see `#89452 <https://github.com/python/cpython/issues/89452>`_ + to ``gdbm``; see `#89452 <https://github.com/python/cpython/issues/89452>`__ for details.) .. tab:: MacPorts For **MacPorts**, install dependencies using ``port``:: - $ sudo port install pkgconfig openssl xz gdbm tcl tk +quartz mpdecimal + $ sudo port install pkgconfig openssl xz gdbm tk +quartz mpdecimal zstd .. tab:: Python 3.13+ @@ -771,7 +915,7 @@ some of CPython's modules (for example, ``zlib``). And finally, run ``make``:: - $ make -s -j2 + $ make -s -j8 There will sometimes be optional modules added for a new release which won't yet be identified in the OS-level build dependencies. In those cases, @@ -782,10 +926,7 @@ some of CPython's modules (for example, ``zlib``). For more details on various options and considerations for building, refer to the `macOS README - <https://github.com/python/cpython/blob/main/Mac/README.rst>`_. - - .. _clang: https://clang.llvm.org/ - .. _ccache: https://ccache.dev/ + <https://github.com/python/cpython/blob/main/Mac/README.rst>`__. .. note:: While you need a C compiler to build CPython, you don't need any knowledge of the C language to contribute! Vast areas of CPython are @@ -825,16 +966,20 @@ some of CPython's modules (for example, ``zlib``). CPython. If you use the pre-compiled binaries, you should unpack each tarball into a separate folder, and use that folder as the configuration target. +.. c_install_dependencies_end + .. _regenerate_configure: Regenerate ``configure`` ======================== +.. c_regenerate_configure_start + If a change is made to Python which relies on some POSIX system-specific functionality (such as using a new system call), it is necessary to update the :cpy-file:`configure` script to test for availability of the functionality. Python's :file:`configure` script is generated from :cpy-file:`configure.ac` -using `GNU Autoconf <https://www.gnu.org/software/autoconf/>`_. +using `GNU Autoconf <https://www.gnu.org/software/autoconf/>`__. After editing :file:`configure.ac`, run ``make regen-configure`` to generate :file:`configure`, :cpy-file:`pyconfig.h.in`, and :cpy-file:`aclocal.m4`. @@ -868,19 +1013,21 @@ and make sure the :file:`pkg.m4` macro file located in the appropriate :program:`autoreconf` runs :program:`autoconf` and a number of other tools repeatedly as appropriate. -.. _build_troubleshooting: +.. c_regenerate_configure_end Regenerate the ABI dump ======================= +.. c_regenerate_abi_start + Maintenance branches (not ``main``) have a special file located in -``Doc/data/pythonX.Y.abi`` that allows us to know if a given Pull Request +``Doc/data/pythonX.Y.abi`` that allows us to know if a given pull request affects the public ABI. This file is used by the GitHub CI in a check -called ``Check if the ABI has changed`` that will fail if a given Pull Request +called ``Check if the ABI has changed`` that will fail if a given pull request has changes to the ABI and the ABI file is not updated. -This check acts as a fail-safe and **doesn't necessarily mean that the Pull -Request cannot be merged**. When this check fails you should add the relevant +This check acts as a fail-safe and **doesn't necessarily mean that the pull +request cannot be merged**. When this check fails you should add the relevant release manager to the PR so that they are aware of the change and they can validate if the change can be made or not. @@ -909,9 +1056,15 @@ Note that the ``ubuntu`` version used to execute the script matters and **must** match the version used by the CI to check the ABI. See the ``.github/workflows/build.yml`` file for more information. +.. c_regenerate_abi_end + +.. _build_troubleshooting: + Troubleshoot the build ====================== +.. c_build_troubleshooting_start + This section lists some of the common problems that may arise during the compilation of Python, with proposed solutions. @@ -930,6 +1083,8 @@ To overcome this problem, auto-generated files are also checked into the Git repository. So if you don't touch the auto-generation scripts, there's no real need to auto-generate anything. +.. c_build_troubleshooting_end + Editors and tools ================= @@ -940,11 +1095,13 @@ support. For editors and tools which the core developers have felt some special comment is needed for coding *in* Python, see :ref:`resources`. -.. _build-directory-structure: +.. _build_directory_structure: Directory structure =================== +.. c_directory_structure_start + There are several top-level directories in the CPython source tree. Knowing what each one is meant to hold will help you find where a certain piece of functionality is implemented. Do realize, though, there are always exceptions to @@ -955,7 +1112,7 @@ every rule. See also :ref:`building-doc`. ``Grammar`` - Contains the :abbr:`EBNF (Extended Backus-Naur Form)` grammar file for + Contains the :abbr:`PEG (Parser Expression Grammar)` grammar file for Python. ``Include`` @@ -1000,29 +1157,39 @@ every rule. ``Tools`` Various tools that are (or have been) used to maintain Python. +.. c_directory_structure_end + -.. _issue tracker: https://github.com/python/cpython/issues +.. _using-a-container: +Using a container +================= + +There are various ways to use a container to build CPython without installing +additional tools on your machine. All approaches use the container defined in +the `cpython-devcontainers repo`_ in some way. .. _using-codespaces: Contribute using GitHub Codespaces -================================== +---------------------------------- + +.. c_codespaces_start .. _codespaces-whats-codespaces: What is GitHub Codespaces? --------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^ If you'd like to start contributing to CPython without needing to set up a local developer environment, you can use -`GitHub Codespaces <https://github.com/features/codespaces>`_. +`GitHub Codespaces <https://github.com/features/codespaces>`__. Codespaces is a cloud-based development environment offered by GitHub that allows developers to write, build, test, and debug code directly within their web browser or in Visual Studio Code (VS Code). To help you get started, CPython contains a -`devcontainer folder <https://github.com/python/cpython/tree/main/.devcontainer>`_ +`devcontainer folder <https://github.com/python/cpython/tree/main/.devcontainer>`__ with a JSON configuration file that provides consistent and versioned codespace configurations for all users of the project. It also contains a Dockerfile that allows you to set up the same environment but locally in a Docker container if @@ -1031,22 +1198,36 @@ you'd prefer to use that directly. .. _codespaces-create-a-codespace: Create a CPython codespace --------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^ Here are the basic steps needed to contribute a pull request using Codespaces. You first need to navigate to the -`CPython repo <https://github.com/python/cpython>`_ hosted on GitHub. +`CPython repo <https://github.com/python/cpython>`__ hosted on GitHub. Then you will need to: -1. Press the ``,`` key to launch the codespace setup screen for the current - branch (alternatively, click the green :guilabel:`Code` button and choose - the ``codespaces`` tab and then press the - green :guilabel:`Create codespace on main` button). +1. Launch the codespace + + - Press the ``,`` key to launch the codespace setup screen for the current + branch + + - For the default dev container (which is what you very likely want), click + the green :guilabel:`Create new codespace` button + - For alternative containers, click :guilabel:`Change options` and + choose the appropriate container + + - Alternatively, click the green :guilabel:`Code` button and choose + the :guilabel:`codespaces` tab + + - For the default dev container (which is what you very likely want), click + the green :guilabel:`Create codespace on main` button + - For alternative containers, go to the :guilabel:`…` menu and choose + :guilabel:`New with options…` + 2. A screen should appear that lets you know your codespace is being set up. (Note: Since the CPython devcontainer is provided, codespaces will use the configuration it specifies.) -3. A `web version of VS Code <https://vscode.dev/>`_ will open inside your web +3. A `web version of VS Code <https://vscode.dev/>`__ will open inside your web browser, already linked up with your code and a terminal to the remote codespace where CPython and its documentation have already been built. 4. Use the terminal with the usual Git commands to create a new branch, commit @@ -1060,7 +1241,7 @@ up from where you left off! .. _codespaces-use-locally: Use Codespaces locally ----------------------- +^^^^^^^^^^^^^^^^^^^^^^ On the bottom left side of the codespace screen you will see a green or grey square that says :guilabel:`Codespaces`. You can click this for additional @@ -1069,5 +1250,97 @@ select the option ``Open in VS Code``. You will still be working on the remote codespace instance, thus using the remote instance's compute power. The compute power may be a much higher spec than your local machine which can be helpful. +.. c_codespaces_end + +.. _devcontainer-directly: + +Using the dev container directly +-------------------------------- + +If you want more control over the environment, or to work offline, +you can use the same container used in +:ref:`GitHub Codespaces <using-codespaces>` directly. +This is meant for users who have (or want to get) some experience +with containers. +These instructions assume a Unix-like environment with +`Docker <https://www.docker.com/>`__ or `Podman <https://podman.io/>`__ +installed. The instructions also assume you want the default dev container; +tweak the commands as appropriate if you want to use an alternative container +(e.g. the WASI dev container). + +.. _devcontainer-image: + +Using the pre-built container image +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +`Dev container images <https://github.com/python/cpython-devcontainers/pkgs/container/devcontainer>`__ +are available from the +`GitHub Container Registry (GHCR) account for the Python org <https://github.com/orgs/python/packages>`__. + +To run the container and launch a Bash shell, run one of the following commands +in a clone of the CPython repository. + +.. tab:: Podman + + .. code-block:: bash + + podman run -it --rm --volume $PWD:/workspace:Z --workdir /workspace ghcr.io/python/devcontainer:latest + +.. tab:: Docker + + .. code-block:: bash + + docker run -it --rm --volume $PWD:/workspace --workdir /workspace ghcr.io/python/devcontainer:latest + + +Note that the container has read/write access to the working directory. +You may want to use a separate clone of CPython, or run ``make clean`` +to remove caches and build output generated for your host OS. + +.. _devcontainer-build: + +Building yourself +^^^^^^^^^^^^^^^^^ + +If you prefer, you can build the container image yourself. In a clone of the +`cpython-devcontainers repo`_, +build the container and name it ``cpython-dev``: + +.. tab:: Podman + + .. code-block:: shell + + podman build devcontainer/ --tag cpython-dev + +.. tab:: Docker + + .. code-block:: shell + + docker build devcontainer/ --tag cpython-dev + +The same command will update any existing ``cpython-dev`` container. +Run it again from time to time -- especially if the container stops +working for you. + +To run the container and launch a Bash shell, run one of the following commands +in a clone of the CPython repository. + +.. tab:: Podman + + .. code-block:: shell + + podman run -it --rm --volume $PWD:/workspace:Z --workdir /workspace cpython-dev bash + +.. tab:: Docker + + .. code-block:: shell + + docker run -it --rm --volume $PWD:/workspace --workdir /workspace cpython-dev bash + + +The same caveats outlined above when running from a container image from GHCR +also apply here. + -.. TODO: add docker instructions +.. _cpython-devcontainers repo: https://github.com/python/cpython-devcontainers +.. include:: ../links.rst diff --git a/include/activate-tab.rst b/include/activate-tab.rst new file mode 100644 index 0000000000..229542bf42 --- /dev/null +++ b/include/activate-tab.rst @@ -0,0 +1,7 @@ +.. raw:: html + + <script> + document.addEventListener('DOMContentLoaded', function() { + activateTab(getOS()); + }); + </script> diff --git a/include/release-cycle.json b/include/release-cycle.json deleted file mode 100644 index b77e904879..0000000000 --- a/include/release-cycle.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "3.14": { - "branch": "main", - "pep": 745, - "status": "feature", - "first_release": "2025-10-01", - "end_of_life": "2030-10", - "release_manager": "Hugo van Kemenade" - }, - "3.13": { - "branch": "3.13", - "pep": 719, - "status": "bugfix", - "first_release": "2024-10-07", - "end_of_life": "2029-10", - "release_manager": "Thomas Wouters" - }, - "3.12": { - "branch": "3.12", - "pep": 693, - "status": "bugfix", - "first_release": "2023-10-02", - "end_of_life": "2028-10", - "release_manager": "Thomas Wouters" - }, - "3.11": { - "branch": "3.11", - "pep": 664, - "status": "security", - "first_release": "2022-10-24", - "end_of_life": "2027-10", - "release_manager": "Pablo Galindo Salgado" - }, - "3.10": { - "branch": "3.10", - "pep": 619, - "status": "security", - "first_release": "2021-10-04", - "end_of_life": "2026-10", - "release_manager": "Pablo Galindo Salgado" - }, - "3.9": { - "branch": "3.9", - "pep": 596, - "status": "security", - "first_release": "2020-10-05", - "end_of_life": "2025-10", - "release_manager": "Łukasz Langa" - }, - "3.8": { - "branch": "3.8", - "pep": 569, - "status": "end-of-life", - "first_release": "2019-10-14", - "end_of_life": "2024-10-07", - "release_manager": "Łukasz Langa" - }, - "3.7": { - "branch": "3.7", - "pep": 537, - "status": "end-of-life", - "first_release": "2018-06-27", - "end_of_life": "2023-06-27", - "release_manager": "Ned Deily" - }, - "3.6": { - "branch": "3.6", - "pep": 494, - "status": "end-of-life", - "first_release": "2016-12-23", - "end_of_life": "2021-12-23", - "release_manager": "Ned Deily" - }, - "3.5": { - "branch": "3.5", - "pep": 478, - "status": "end-of-life", - "first_release": "2015-09-13", - "end_of_life": "2020-09-30", - "release_manager": "Larry Hastings" - }, - "3.4": { - "branch": "3.4", - "pep": 429, - "status": "end-of-life", - "first_release": "2014-03-16", - "end_of_life": "2019-03-18", - "release_manager": "Larry Hastings" - }, - "3.3": { - "branch": "3.3", - "pep": 398, - "status": "end-of-life", - "first_release": "2012-09-29", - "end_of_life": "2017-09-29", - "release_manager": "Georg Brandl, Ned Deily (3.3.7+)" - }, - "3.2": { - "branch": "3.2", - "pep": 392, - "status": "end-of-life", - "first_release": "2011-02-20", - "end_of_life": "2016-02-20", - "release_manager": "Georg Brandl" - }, - "2.7": { - "branch": "2.7", - "pep": 373, - "status": "end-of-life", - "first_release": "2010-07-03", - "end_of_life": "2020-01-01", - "release_manager": "Benjamin Peterson" - }, - "3.1": { - "branch": "3.1", - "pep": 375, - "status": "end-of-life", - "first_release": "2009-06-27", - "end_of_life": "2012-04-09", - "release_manager": "Benjamin Peterson" - }, - "3.0": { - "branch": "3.0", - "pep": 361, - "status": "end-of-life", - "first_release": "2008-12-03", - "end_of_life": "2009-06-27", - "release_manager": "Barry Warsaw" - }, - "2.6": { - "branch": "2.6", - "pep": 361, - "status": "end-of-life", - "first_release": "2008-10-01", - "end_of_life": "2013-10-29", - "release_manager": "Barry Warsaw" - } -} diff --git a/index.rst b/index.rst index 9dbc06908b..18aca244e1 100644 --- a/index.rst +++ b/index.rst @@ -4,34 +4,86 @@ Python Developer's Guide ======================== -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: include/activate-tab.rst .. highlight:: bash This guide is a comprehensive resource for :ref:`contributing <contributing>` to Python_ -- for both new and experienced contributors. It is :ref:`maintained <devguide>` by the same -community that maintains Python. We welcome your contributions to Python! +community that maintains Python. We welcome your contributions! + + +.. _contributing: + +Contributing +------------ + +We encourage everyone to contribute to Python. To help you, we have put up this +developer's guide. If you still have questions after reviewing the material in +this guide, then the `Core Python Mentorship`_ group is available to help guide new +contributors through the process. + +Guide for contributing to Python: + +.. list-table:: + :widths: 10 10 10 + :header-rows: 1 + + * - Documentation + - Code + - Triage + * - + * :ref:`docquality` + * :ref:`documenting` + * :ref:`style-guide` + * :ref:`rst-primer` + * :ref:`translating` + * :ref:`devguide` + - + * :ref:`setup` + * :ref:`help` + * :ref:`pullrequest` + * :ref:`runtests` + * :ref:`fixingissues` + * :ref:`communication` + * :ref:`gitbootcamp` + * :ref:`devcycle` + - + * :ref:`tracker` + * :ref:`triaging` + * :ref:`helptriage` + * :ref:`experts` + * :ref:`labels` + * :ref:`gh-faq` + * :ref:`triage-team` + +We **recommend** that sections of this guide be read as needed. You +can stop where you feel comfortable and begin contributing immediately without +reading and understanding everything. If you do choose to skip +around within the guide, be aware that sections build on each other, +so you may find it necessary to backtrack to fill in +missing concepts and terminology. + +A number of individuals from the Python community have contributed to a series +of excellent guides at `Open Source Guides <https://opensource.guide/>`__. +For example, +`How to Contribute to Open Source <https://opensource.guide/how-to-contribute/>`__. + .. _quick-reference: Quick reference --------------- -Here are the basic steps needed to get set up and contribute a pull request. +Here are the basic steps needed to get set up and open a pull request. This is meant as a checklist, once you know the basics. For complete instructions please see the :ref:`setup guide <setup>`. 1. Install and set up :ref:`Git <vcsetup>` and other dependencies (see the :ref:`Git Setup <setup>` page for detailed information). -2. Fork `the CPython repository <https://github.com/python/cpython>`_ +2. Fork `the CPython repository <https://github.com/python/cpython>`__ to your GitHub account and :ref:`get the source code <checkout>` using:: git clone https://github.com/<your_username>/cpython @@ -43,13 +95,13 @@ instructions please see the :ref:`setup guide <setup>`. .. code-block:: shell - ./configure --with-pydebug && make -j + ./configure --with-pydebug && make -j $(nproc) .. tab:: macOS .. code-block:: shell - ./configure --with-pydebug && make -j + ./configure --with-pydebug && make -j8 .. tab:: Windows @@ -74,11 +126,12 @@ instructions please see the :ref:`setup guide <setup>`. .. code-block:: shell - ./python.exe -m test -j3 + ./python.exe -m test -j8 - Note: :ref:`Most <mac-python.exe>` macOS systems use - :file:`./python.exe` in order to avoid filename conflicts with - the ``Python`` directory. + .. note:: + :ref:`Most <mac-python.exe>` macOS systems use + :file:`./python.exe` in order to avoid filename conflicts with + the ``Python`` directory. .. tab:: Windows @@ -91,44 +144,22 @@ instructions please see the :ref:`setup guide <setup>`. git checkout -b fix-issue-12345 main If an issue does not already exist, please `create it - <https://github.com/python/cpython/issues>`_. Trivial issues (for example, typo fixes) do - not require any issue to be created. - -6. Once you fixed the issue, run the tests, and the patchcheck: - - .. tab:: Unix - - .. code-block:: shell - - make patchcheck - - .. tab:: macOS + <https://github.com/python/cpython/issues>`__. Trivial issues (for example, typos) do + not require an issue. - .. code-block:: shell - - make patchcheck - - .. tab:: Windows - - .. code-block:: dosbatch - - .\python.bat Tools\patchcheck\patchcheck.py - - If everything is ok, commit. - -7. Push the branch on your fork on GitHub and :ref:`create a pull request - <pullrequest>`. Include the issue number using ``gh-NNNN`` in the - pull request description. For example: +6. Push the branch on your fork on GitHub and :ref:`create a pull request + <pullrequest>`. Include the issue number using ``gh-NNNNNN`` in the + pull request title. For example: .. code-block:: text gh-12345: Fix some bug in spam module -8. Add a News entry into the ``Misc/NEWS.d`` directory as individual file. The - news entry can be created by using `blurb-it <https://blurb-it.herokuapp.com/>`_, +7. Add a News entry into the ``Misc/NEWS.d/`` directory as individual file. The + news entry can be created by using `blurb-it <https://blurb-it.herokuapp.com/>`__, or the :pypi:`blurb` tool and its ``blurb add`` command. Please read more about ``blurb`` in its - `repository <https://github.com/python/blurb>`_. + `repository <https://github.com/python/blurb>`__. .. note:: @@ -136,58 +167,6 @@ instructions please see the :ref:`setup guide <setup>`. Agreement (CLA) as described in the :ref:`Licensing <cla>` section of this guide. -Quick links ------------ - -Here are some links that you probably will reference frequently while -contributing to Python: - -* `Issue tracker`_ -* `Buildbot status`_ -* :ref:`help` -* PEPs_ (Python Enhancement Proposals) -* :ref:`gitbootcamp` - -.. _contributing: - -Contributing ------------- - -We encourage everyone to contribute to Python and that's why we have put up this -developer's guide. If you still have questions after reviewing the material in -this guide, then the `Core Python Mentorship`_ group is available to help guide new -contributors through the process. - -A number of individuals from the Python community have contributed to a series -of excellent guides at `Open Source Guides <https://opensource.guide/>`_. - -Core developers and contributors alike will find the following guides useful: - -* `How to Contribute to Open Source <https://opensource.guide/how-to-contribute/>`_ -* `Building Welcoming Communities <https://opensource.guide/building-community/>`_ - -Guide for contributing to Python: - -======================== =================== ======================= ======================= -Contributors Documentarians Triagers Core Developers -======================== =================== ======================= ======================= -:ref:`setup` :ref:`docquality` :ref:`tracker` :ref:`responsibilities` -:ref:`help` :ref:`documenting` :ref:`triaging` :ref:`developers` -:ref:`pullrequest` :ref:`style-guide` :ref:`helptriage` :ref:`committing` -:ref:`runtests` :ref:`rst-primer` :ref:`experts` :ref:`devcycle` -:ref:`fixingissues` :ref:`translating` :ref:`labels` :ref:`motivations` -:ref:`communication` :ref:`devguide` :ref:`gh-faq` :ref:`experts` -:ref:`gitbootcamp` :ref:`triage-team` -:ref:`devcycle` -======================== =================== ======================= ======================= - -We **recommend** that the documents in this guide be read as needed. You -can stop where you feel comfortable and begin contributing immediately without -reading and understanding these documents all at once. If you do choose to skip -around within the documentation, be aware that it is written assuming preceding -documentation has been read so you may find it necessary to backtrack to fill in -missing concepts and terminology. - Proposing changes to Python itself ---------------------------------- @@ -206,34 +185,6 @@ happen and that process is also described as part of this guide: * :ref:`langchanges` -Other interpreter implementations ---------------------------------- - -This guide is specifically for contributing to the Python reference interpreter, -also known as CPython (while most of the standard library is written in Python, -the interpreter core is written in C and integrates most easily with the C and -C++ ecosystems). - -There are other Python implementations, each with a different focus. Like -CPython, they always have more things they would like to do than they have -developers to work on them. Some major examples that may be of interest are: - -* PyPy_: A Python interpreter focused on high speed (JIT-compiled) operation - on major platforms -* Jython_: A Python interpreter focused on good integration with the Java - Virtual Machine (JVM) environment -* IronPython_: A Python interpreter focused on good integration with the - Common Language Runtime (CLR) provided by .NET and Mono -* Stackless_: A Python interpreter focused on providing lightweight - microthreads while remaining largely compatible with CPython specific - extension modules -* MicroPython_: A tiny Python interpreter with small subset of the Python - standard library that is optimised to run on microcontrollers and in - constrained environments. -* CircuitPython_: A fork of MicroPython designed to simplify experimenting - and learning to code on low-cost microcontroller boards. - - Key resources ------------- @@ -249,12 +200,15 @@ Key resources * `Buildbot status`_ * Source code - * `Browse online <https://github.com/python/cpython/>`_ - * `Snapshot of the *main* branch <https://github.com/python/cpython/archive/main.zip>`_ + * `Browse online <https://github.com/python/cpython/>`__ + * `Download a snapshot <https://github.com/python/cpython/archive/main.zip>`__ + of the ``main`` branch * PEPs_ (Python Enhancement Proposals) +* `The Python Discourse <https://discuss.python.org/>`__ * :ref:`help` * :ref:`developers` +* :ref:`gitbootcamp` .. _resources: @@ -265,40 +219,59 @@ Additional resources * Anyone can clone the sources for this guide. See :ref:`devguide`. * Help with ... - * :ref:`exploring` + * :ref:`internals` * :ref:`grammar` - * :ref:`parser` - * :ref:`compiler` - * :ref:`garbage_collector` * Tool support * :ref:`gdb` * :ref:`clang` - * Various tools with configuration files as found in the `Misc directory`_ - * Information about editors and their configurations can be found in the - `wiki <https://wiki.python.org/moin/PythonEditors>`_ + * Various tools with configuration files as found in the + :cpy-file:`Misc/` directory * `python.org maintenance`_ -* :ref:`Search this guide <search>` Code of conduct --------------- + Please note that all interactions on `Python Software Foundation <https://www.python.org/psf-landing/>`__-supported infrastructure is `covered <https://www.python.org/psf/records/board/minutes/2014-01-06/#management-of-the-psfs-web-properties>`__ by the `PSF Code of Conduct <https://policies.python.org/python.org/code-of-conduct/>`__, which includes all infrastructure used in the development of Python itself -(for example, mailing lists, issue trackers, GitHub, etc.). +(for example, Discourse, issue trackers, GitHub, and so on). In general this means everyone is expected to be open, considerate, and respectful of others no matter what their position is within the project. -Status of Python branches -------------------------- -Moved to :ref:`versions` +Other interpreter implementations +--------------------------------- + +This guide is specifically for contributing to the Python reference interpreter, +also known as CPython (while most of the standard library is written in Python, +the interpreter core is written in C and integrates most easily with the C and +C++ ecosystems). + +There are other Python implementations, each with a different focus. Like +CPython, they always have more things they would like to do than they have +developers to work on them. Some major examples that may be of interest are: + +* PyPy_: A Python interpreter focused on high speed (JIT-compiled) operation + on major platforms. +* GraalPy_: A Python interpreter which has first-class support for + embedding in Java, built on GraalVM. +* Jython_: A Python interpreter focused on good integration with the Java + Virtual Machine (JVM) environment. +* IronPython_: A Python interpreter focused on good integration with the + Common Language Runtime (CLR) provided by .NET and Mono. +* MicroPython_: A tiny Python interpreter with small subset of the Python + standard library that is optimised to run on microcontrollers and in + constrained environments. +* CircuitPython_: A fork of MicroPython designed to simplify experimenting + and learning to code on low-cost microcontroller boards. + .. _contents: @@ -314,21 +287,20 @@ Full table of contents documentation/index testing/index development-tools/index - core-developers/index - internals/index + core-team/index + internals versions - contrib/index -.. _Buildbot status: https://www.python.org/dev/buildbot/ -.. _Misc directory: https://github.com/python/cpython/tree/main/Misc + +.. _Buildbot status: https://buildbot.python.org/ .. _PEPs: https://peps.python.org/ .. _python.org maintenance: https://pythondotorg.readthedocs.io/ .. _Python: https://www.python.org/ .. _Core Python Mentorship: https://www.python.org/dev/core-mentorship/ .. _PyPy: https://pypy.org +.. _GraalPy: https://www.graalvm.org/python/ .. _Jython: https://www.jython.org/ .. _IronPython: https://ironpython.net/ -.. _Stackless: https://github.com/stackless-dev/stackless/wiki/ .. _MicroPython: https://micropython.org/ .. _CircuitPython: https://circuitpython.org/ .. _Issue tracker: https://github.com/python/cpython/issues diff --git a/internals/exploring.rst b/internals.rst similarity index 67% rename from internals/exploring.rst rename to internals.rst index 0ae8337e8c..89897eb19c 100644 --- a/internals/exploring.rst +++ b/internals.rst @@ -1,53 +1,9 @@ -.. _exploring: +.. _internals: =================== -CPython source code +CPython's internals =================== -This section gives an overview of CPython's code structure and provides -a summary of file locations for modules and built-ins. - - -Source code layout -================== - -For a Python :term:`module`, the typical layout is: - -* :file:`Lib/{<module>}.py` -* :file:`Modules/_{<module>}.c` (if there's also a C accelerator module) -* :file:`Lib/test/test_{<module>}.py` -* :file:`Doc/library/{<module>}.rst` - -For an :term:`extension module`, the typical layout is: - -* :file:`Modules/{<module>}module.c` -* :file:`Lib/test/test_{<module>}.py` -* :file:`Doc/library/{<module>}.rst` - -For :ref:`bltin-types`, the typical layout is: - -* :file:`Objects/{<builtin>}object.c` -* :file:`Lib/test/test_{<builtin>}.py` -* :cpy-file:`Doc/library/stdtypes.rst` - -For :ref:`built-in-funcs`, the typical layout is: - -* :cpy-file:`Python/bltinmodule.c` -* :cpy-file:`Lib/test/test_builtin.py` -* :cpy-file:`Doc/library/functions.rst` - -Some exceptions to these layouts are: - -* built-in type ``int`` is at :cpy-file:`Objects/longobject.c` -* built-in type ``str`` is at :cpy-file:`Objects/unicodeobject.c` -* built-in module ``sys`` is at :cpy-file:`Python/sysmodule.c` -* built-in module ``marshal`` is at :cpy-file:`Python/marshal.c` -* Windows-only module ``winreg`` is at :cpy-file:`PC/winreg.c` - - -Additional references -===================== - The CPython code base is constantly changing and evolving. Here's a sample of references about CPython's architecture aimed at building your understanding of CPython internals and its evolution: @@ -56,6 +12,7 @@ building your understanding of CPython internals and its evolution: :header: "Title", "Brief", "Author", "Version" :widths: 50, 50, 20, 5 + "`CPython's InternalDocs`_", "Docs on CPython internals maintained in the source tree", "", "" "`A guide from parser to objects, observed using GDB`_", "Code walk from Parser, AST, Sym Table and Objects", Louie Lu, 3.7.a0 "`Green Tree Snakes`_", "The missing Python AST docs", Thomas Kluyver, 3.6 "`Yet another guided tour of CPython`_", "A guide for how CPython REPL works", Guido van Rossum, 3.5 @@ -72,6 +29,7 @@ building your understanding of CPython internals and its evolution: "`A guide from parser to objects, observed using Eclipse`_", "Code walk from Parser, AST, Sym Table and Objects", Prashanth Raghu, 2.7.12 "`CPython internals: A ten-hour codewalk through the Python interpreter source code`_", "Code walk from source code to generators", Philip Guo, 2.7.8 +.. _CPython's InternalDocs: https://github.com/python/cpython/blob/main/InternalDocs/README.md .. _A guide from parser to objects, observed using GDB: https://hackmd.io/s/ByMHBMjFe diff --git a/internals/compiler.rst b/internals/compiler.rst deleted file mode 100644 index 5b43e1e6dc..0000000000 --- a/internals/compiler.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _compiler: - -=============== -Compiler design -=============== - -.. highlight:: none - -This document is now part of the -`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/compiler.md>`_. diff --git a/internals/garbage-collector.rst b/internals/garbage-collector.rst deleted file mode 100644 index acbcedf0e8..0000000000 --- a/internals/garbage-collector.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _garbage-collector: -.. _gc: -.. _garbage_collector: - -======================== -Garbage collector design -======================== - -.. highlight:: none - -This document is now part of the -`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/garbage_collector.md>`_. diff --git a/internals/index.rst b/internals/index.rst deleted file mode 100644 index 05723f4824..0000000000 --- a/internals/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _internals: - -=================== -CPython's internals -=================== - -This guide describes the basics of CPython's internals. -It explains the layout of CPython's source code. -It also explains how the parser, compiler, and interpreter -work together to run your Python code. -Finally, it covers the garbage collector and how it manages memory. - -.. toctree:: - :maxdepth: 3 - - exploring - parser - compiler - interpreter - garbage-collector diff --git a/internals/interpreter.rst b/internals/interpreter.rst deleted file mode 100644 index a7ae39c120..0000000000 --- a/internals/interpreter.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _interpreter: - -======================== -The bytecode interpreter -======================== - -This document is now part of the -`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/interpreter.md>`_. diff --git a/internals/parser.rst b/internals/parser.rst deleted file mode 100644 index 688ad61e77..0000000000 --- a/internals/parser.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _parser: - -=================== -Guide to the parser -=================== - -.. highlight:: none - -This document is now part of the -`CPython Internals Docs <https://github.com/python/cpython/blob/main/InternalDocs/parser.md>`_. diff --git a/links.rst b/links.rst new file mode 100644 index 0000000000..4f0eb58814 --- /dev/null +++ b/links.rst @@ -0,0 +1,6 @@ +.. Links for use anywhere. Include this file to use them. + +.. _issue tracker: https://github.com/python/cpython/issues + +.. _clang: https://clang.llvm.org/ +.. _ccache: https://ccache.dev/ diff --git a/make.bat b/make.bat index b486783665..fec822e953 100644 --- a/make.bat +++ b/make.bat @@ -11,7 +11,7 @@ if "%PYTHON%" == "" ( ) set BUILDDIR=_build -set SPHINXOPTS=--fail-on-warning --keep-going +set SPHINXOPTS=--fail-on-warning set _ALL_SPHINX_OPTS=%SPHINXOPTS% if "%1" == "check" goto check diff --git a/make.ps1 b/make.ps1 index 71a8f56f4c..c8ad842c9b 100644 --- a/make.ps1 +++ b/make.ps1 @@ -8,7 +8,7 @@ Set-StrictMode -Version 3.0 $ErrorActionPreference = "Stop" $BUILDDIR = "_build" -$SPHINXOPTS = "--fail-on-warning --keep-going" +$SPHINXOPTS = "--fail-on-warning" $_ALL_SPHINX_OPTS = $SPHINXOPTS $_PYTHON = $Env:PYTHON ?? "py -3" @@ -64,7 +64,8 @@ if ($target -Eq "clean") { $ToClean = @( $BUILDDIR, $_VENV_DIR, - "include/branches.csv", "include/end-of-life.csv", "include/release-cycle.svg" + "include/branches.csv", "include/end-of-life.csv", + "_static/release-cycle.svg", "_static/release-cycle-all.svg" ) foreach ($item in $ToClean) { if (Test-Path -Path $item) { diff --git a/requirements.txt b/requirements.txt index fe0a5348f4..3b40508f67 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,11 @@ furo>=2022.6.4 jinja2 +linklint sphinx-autobuild>=2024.9.19 sphinx-inline-tabs>=2023.4.21 -sphinx-lint==1.0.0 +sphinx-lint==1.0.2 sphinx-notfound-page>=1.0.0 sphinx_copybutton>=0.3.3 -sphinxext-opengraph>=0.7.1 +sphinxext-opengraph>=0.13.0 sphinxext-rediraffe -Sphinx~=8.1.3 +Sphinx>=8.2.3 diff --git a/testing/buildbots.rst b/testing/buildbots.rst index 97856f7132..fc420d3f79 100644 --- a/testing/buildbots.rst +++ b/testing/buildbots.rst @@ -11,35 +11,38 @@ branches <devcycle>`, Python has a set of dedicated machines (called *buildbots* or *build workers*) used for continuous integration. They span a number of hardware/operating system combinations. Furthermore, each machine hosts several *builders*, one per active branch: when a new change is pushed -to this branch on the public `GitHub repository <https://github.com/python/cpython>`_, all corresponding builders -will schedule a new build to be run as soon as possible. +to this branch on the public `GitHub repository <https://github.com/python/cpython>`__, +all corresponding builders will schedule a new build to be run as soon as possible. -The build steps run by the buildbots are the following: +The build steps run by the buildbots are: * Check out the source tree for the change which triggered the build * Compile Python * Run the test suite using :ref:`strenuous settings <strenuous_testing>` * Clean up the build tree -It is your responsibility, as a core developer, to check the automatic -build results after you push a change to the repository. It is therefore -important that you get acquainted with the way these results are presented, +It is the responsibility of core team members to check the automatic +build results after they push a change to the repository. It is therefore +important that they are acquainted with the way these results are presented, and how various kinds of failures can be explained and diagnosed. + In case of trouble ================== Please read this page in full. If your questions aren't answered here and you need assistance with the buildbots, a good way to get help is to either: -* contact the ``python-buildbots@python.org`` mailing list where all buildbot - worker owners are subscribed; or +* contact the `python-buildbots@python.org + <https://mail.python.org/archives/list/python-buildbots@python.org/>`__ + mailing list where all buildbot worker owners are subscribed; or * contact the release manager of the branch you have issues with. + Buildbot failures on pull requests ================================== -The ``bedevere-bot`` on GitHub will put a message on your merged Pull Request +The Bedevere bot on GitHub will put a message on your merged pull request if building your commit on a stable buildbot worker fails. Take care to evaluate the failure, even if it looks unrelated at first glance. @@ -48,38 +51,66 @@ after each commit. In particular, reference leaks builds take several hours to complete so they are done periodically. This is why it's important for you to be able to check the results yourself, too. + +Triggering on pull requests +=========================== + +To trigger buildbots on a pull request you need to be a CPython triager or a +core team member. If you are not, ask someone to trigger them on your behalf. + +The simplest way to trigger most buildbots on your PR is with the +:gh-label:`🔨 test-with-buildbots` and :gh-label:`🔨 test-with-refleak-buildbots` +labels. (See :ref:`github-pr-labels`.) + +These will run buildbots on the most recent commit. If you want to trigger the +buildbots again on a later commit, you'll have to remove the label and add it +again. + +If you want to test a pull request against specific platforms, you can trigger +one or more buildbots by posting a comment that begins with: + +.. code-block:: none + + !buildbot regex-matching-target + +For example to run both the iOS and Android buildbots, you can use: + +.. code-block:: none + + !buildbot ios|android + +Bedevere will post a comment indicating which buildbots, if +any, were matched. If none were matched, or you do not have the +necessary permissions to trigger a request, it will tell you that too. + +The ``!buildbot`` comment will also only run buildbots on the most recent +commit. To trigger the buildbots again on a later commit, you will have to +repeat the comment. + + Checking results of automatic builds ==================================== -There are three ways of visualizing recent build results: - -* The Web interface for each branch at https://www.python.org/dev/buildbot/, - where the so-called "waterfall" view presents a vertical rundown of recent - builds for each builder. When interested in one build, you'll have to - click on it to know which commits it corresponds to. Note that - the buildbot web pages are often slow to load, be patient. +The Web interface at https://buildbot.python.org/#/ has several ways of +visualizing recent build results: -* The command-line ``bbreport.py`` client, which you can get from - https://code.google.com/archive/p/bbreport. Installing it is trivial: just add - the directory containing ``bbreport.py`` to your system path so that - you can run it from any filesystem location. For example, if you want - to display the latest build results on the development ("main") branch, - type:: +* A `release status dashboard <https://buildbot.python.org/#/release_status>`__ + that shows the status of buildbots for each active branch, + summarizing whether the builds are ready for release. - bbreport.py -q 3.x +* A `waterfall view <https://buildbot.python.org/#/waterfall>`__ + that presents a vertical rundown of recent builds for each builder. + When interested in one build, click on it for more detail such as logs and + which commits it corresponds to. -* The buildbot "console" interface at https://buildbot.python.org/all/ - This works best on a wide, high resolution +* A `console view <https://buildbot.python.org/#/console>`__, + which works best on a wide, high resolution monitor. Clicking on the colored circles will allow you to open a new page containing whatever information about that particular build is of interest to you. You can also access builder information by clicking on the builder status bubbles in the top line. -If you like IRC, having an IRC client open to the #python-dev-notifs channel on -irc.libera.chat is useful. Any time a builder changes state (last build -passed and this one didn't, or vice versa), a message is posted to the channel. -Keeping an eye on the channel after pushing a commits is a simple way to get -notified that there is something you should look in to. +Note that the buildbot web pages are often slow to load, be patient. Some buildbots are much faster than others. Over time, you will learn which ones produce the quickest results after a build, and which ones take the @@ -89,20 +120,24 @@ Also, when several commits are pushed in a quick succession in the same branch, it often happens that a single build is scheduled for all these commits. + Stability ========= -A subset of the buildbots are marked "stable". They are taken into account -when making a new release. The rule is that all stable builders must be free of -persistent failures when the release is cut. It is absolutely **vital** -that core developers fix any issue they introduce on the stable buildbots, -as soon as possible. +A subset of the buildbots are marked as +`"stable" <https://buildbot.python.org/#/builders?tags=%2Bstable>`__. +They are taken into account when making a new release. +The rule is that all tier 1 and 2 stable builders must be free of +persistent failures when the release is cut (see :pep:`11` for more information). +It is absolutely **vital** that core team members fix or revert any issue they +introduce on the stable buildbots, as soon as possible. This does not mean that other builders' test results can be taken lightly, either. Some of them are known for having platform-specific issues that prevent some tests from succeeding (or even terminating at all), but introducing additional failures should generally not be an option. + Flags-dependent failures ======================== @@ -113,11 +148,8 @@ or to Python itself. To reproduce, make sure you use the same flags as the buildbots: they can be found out simply by clicking the **stdio** link for the failing build's tests. For example:: - ./python.exe -Wd -E -bb ./Lib/test/regrtest.py -uall -rwW + ./python -E -m test --slow-ci --timeout=1200 -j2 --junit-xml test-results.xml -j10 -.. note:: - Running ``Lib/test/regrtest.py`` is exactly equivalent to running - ``-m test``. Ordering-dependent failures =========================== @@ -135,31 +167,37 @@ run, and check the beginning of the test output proper. Let's assume, for the sake of example, that the output starts with: .. code-block:: none - :emphasize-lines: 6 + :emphasize-lines: 9 - ./python -Wd -E -bb Lib/test/regrtest.py -uall -rwW - == CPython 3.3a0 (default:22ae2b002865, Mar 30 2011, 13:58:40) [GCC 4.4.5] - == Linux-2.6.36-gentoo-r5-x86_64-AMD_Athlon-tm-_64_X2_Dual_Core_Processor_4400+-with-gentoo-1.12.14 little-endian - == /home/buildbot/buildarea/3.x.ochtman-gentoo-amd64/build/build/test_python_29628 - Testing with flags: sys.flags(debug=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=1, verbose=0, bytes_warning=2, quiet=0) - Using random seed 2613169 - [ 1/353] test_augassign - [ 2/353] test_functools + ./python -E -m test --slow-ci --timeout=2400 -j2 -u-cpu,-urlfetch,-network --junit-xml test-results.xml -j4 + == CPython 3.15.0a6+ (heads/main:d625f7da33b, Feb 13 2026, 17:27:29) [GCC 12.2.0] + == Linux-6.12.20+rpt-rpi-v8-aarch64-with-glibc2.36 little-endian + == Python build: release + == cwd: /home/stan/buildarea/3.x.stan-raspbian.nondebug/build/build/test_python_worker_181905æ + == CPU count: 4 + == encodings: locale=ISO-8859-1 FS=utf-8 + == resources: all,-cpu,-network,-urlfetch + Using random seed: 1000348774 + 0:00:00 load avg: 3.34 Run 500 tests in parallel using 4 worker processes (timeout: 40 min, worker timeout: 45 min) + 0:00:01 load avg: 3.34 [ 1/500] test_colorsys passed + 0:00:01 load avg: 3.34 [ 2/500] test_float passed -You can reproduce the exact same order using:: +You can reproduce the exact same order by adding the ``--randseed 1000348774`` option:: - ./python -Wd -E -bb -m test -uall -rwW --randseed 2613169 + ./python -E -m test --slow-ci --timeout=2400 -j2 -u-cpu,-urlfetch,-network --junit-xml test-results.xml -j4 --randseed 1000348774 It will run the following sequence (trimmed for brevity): .. code-block:: none - [ 1/353] test_augassign - [ 2/353] test_functools - [ 3/353] test_bool - [ 4/353] test_contains - [ 5/353] test_compileall - [ 6/353] test_unicode + [ 1/500] test_colorsys + [ 2/500] test_float + [ 3/500] test.test_io.test_memoryio + [ 4/500] test_profile + [ 5/500] test_picklebuffer + [ 6/500] test_zipimport + [ 7/500] test_devpoll + ... If this is enough to reproduce the failure on your setup, you can then bisect the test sequence to look for the specific interference causing the @@ -167,26 +205,26 @@ failure. Copy and paste the test sequence in a text file, then use the ``--fromfile`` (or ``-f``) option of the test runner to run the exact sequence recorded in that text file:: - ./python -Wd -E -bb -m test -uall -rwW --fromfile mytestsequence.txt + ./python -E -m test --slow-ci --timeout=2400 -j2 -u-cpu,-urlfetch,-network --junit-xml test-results.xml -j4 --fromfile mytestsequence.txt -In the example sequence above, if ``test_unicode`` had failed, you would +In the example sequence above, if ``test_zipimport`` had failed, you would first test the following sequence: .. code-block:: none - [ 1/353] test_augassign - [ 2/353] test_functools - [ 3/353] test_bool - [ 6/353] test_unicode + [ 1/500] test_colorsys + [ 2/500] test_float + [ 3/500] test.test_io.test_memoryio + [ 6/500] test_zipimport And, if it succeeds, the following one instead (which, hopefully, shall fail): .. code-block:: none - [ 4/353] test_contains - [ 5/353] test_compileall - [ 6/353] test_unicode + [ 4/500] test_profile + [ 5/500] test_picklebuffer + [ 6/500] test_zipimport Then, recursively, narrow down the search until you get a single pair of tests which triggers the failure. It is very rare that such an interference @@ -208,7 +246,7 @@ not reach a perfect level of reproducibility. Some of them will sometimes display spurious failures, depending on various conditions. Here are common offenders: -* Network-related tests, such as ``test_poplib``, ``test_urllibnet``, etc. +* Network-related tests, such as ``test_poplib``, ``test_urllibnet``, and so on. Their failures can stem from adverse network conditions, or imperfect thread synchronization in the test code, which often has to run a server in a separate thread. diff --git a/testing/coverage.rst b/testing/coverage.rst index d01141a7dc..48c2efc985 100644 --- a/testing/coverage.rst +++ b/testing/coverage.rst @@ -4,13 +4,7 @@ Increase test coverage ====================== -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst Python development follows a practice that all semantic changes and additions to the language and :abbr:`stdlib (standard library)` are accompanied by @@ -127,7 +121,7 @@ to install coverage. You can now use python without the ./ for the rest of these instructions, as long as your venv is activated. For more info on venv see `Virtual Environment -<https://docs.python.org/3/tutorial/venv.html>`_ documentation. +<https://docs.python.org/3/tutorial/venv.html>`__ documentation. If this does not work for you for some reason, you should try using the in-development version of coverage.py to see if it has been updated as needed. diff --git a/testing/new-buildbot-worker.rst b/testing/new-buildbot-worker.rst index cac7bb63d5..aea43a782a 100644 --- a/testing/new-buildbot-worker.rst +++ b/testing/new-buildbot-worker.rst @@ -20,12 +20,12 @@ to go about setting up a buildbot worker, getting it added, and some hints about buildbot maintenance. Anyone running a buildbot that is part of the fleet should subscribe to the -`python-buildbots <https://mail.python.org/mailman3/lists/python-buildbots.python.org/>`_ +`python-buildbots <https://mail.python.org/mailman3/lists/python-buildbots.python.org/>`__ mailing list. This mailing list is also the place to contact if you want to contribute a buildbot but have questions. As for what kind of buildbot to run...take a look at our `current fleet -<https://buildbot.python.org/all/>`_. Pretty much anything that isn't +<builders_>`__. Pretty much anything that isn't on that list would be interesting: different Linux/Unix distributions, different versions of the various OSes, other OSes if you or someone are prepared to make the test suite actually pass on that new OS. Even if you only @@ -40,14 +40,14 @@ Preparing for buildbot worker setup Since the goal is to build Python from source, the system will need to have everything required to do normal python development: a compiler, a linker, and -(except on windows) the "development" headers for any of the optional modules -(zlib, OpenSSL, etc) supported by the platform. Follow the steps outlined in +(except on Windows) the "development" headers for any of the optional modules +(zlib, OpenSSL, and so on) supported by the platform. Follow the steps outlined in :ref:`setup` for the target platform, all the way through to having a working -compiled python. +compiled Python. In order to set up the buildbot software, you will need to obtain an identifier and password for your worker so it can join the fleet. Open an issue in the -`configuration repository <https://github.com/python/buildmaster-config/issues/new/choose>`_ +`configuration repository <https://github.com/python/buildmaster-config/issues/new?template=new_worker.yml>`__ to discuss adding your worker and to obtain the needed workername and password. You can do some of the steps that follow before having the credentials, but it is easiest to have them before @@ -60,209 +60,451 @@ Setting up the buildbot worker Conventional always-on machines ------------------------------- -You need a recent version of the `buildbot <https://buildbot.net/>`_ software, -and you will probably want a separate 'buildbot' user to run the buildbot -software. You may also want to set the buildbot up using a virtual -environment, depending on how you manage your system. We won't cover how to that -here; it doesn't differ from setting up a virtual environment for any other -software, but you'll need to modify the sequence of steps below as appropriate -if you choose that path. +You need a recent version of the `buildbot <https://buildbot.net/>`__ worker +software. On most platforms the distribution's package manager provides the +``buildbot-worker`` package, which also creates a dedicated service account, +systemd unit (or equivalent), and the necessary directories. For platforms +where no package exists, ``pip install buildbot-worker`` is the fallback, but +you will need to create the service account, directories, and service unit +manually. You may also want to set the buildbot up using a virtual +environment, depending on how you manage your system; you'll need to adjust +the steps below as appropriate if you choose that path. -For Linux: +.. tab:: Linux -* If your package manager provides the buildbot worker software, that is - probably the best way to install it; it may create the buildbot user for - you, in which case you can skip the next step. Otherwise, do ``pip install - buildbot-worker`` or ``pip3 install buildbot-worker``. -* Create a ``buildbot`` user (using, eg: ``useradd``) if necessary. -* Log in as the buildbot user. + .. tab:: Fedora / RHEL / CentOS -For Mac: + **Fedora**:: -* Create a buildbot user using the OS/X control panel user admin. It - should be a "standard" user. -* Log in as the buildbot user. -* Install the buildbot worker [#]_ by running ``pip install buildbot-worker``. + dnf install buildbot-worker -For Windows: + **RHEL 8** (requires EPEL):: -* Create a buildbot user as a "standard" user. -* Install the latest version of Python from python.org. -* Open a Command Prompt. -* Execute ``python -m pip install pypiwin32 buildbot-worker`` (note that - ``python.exe`` is not added to ``PATH`` by default, making the - ``python`` command accessible is left as an exercise for the user). + subscription-manager repos --enable codeready-builder-for-rhel-8-$(arch)-rpms + dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm + dnf install buildbot-worker -In a terminal window for the buildbot user, issue the following commands (you -can put the ``buildarea`` wherever you want to):: + **RHEL 9** (requires EPEL):: - mkdir buildarea - buildbot-worker create-worker buildarea buildbot-api.python.org:9020 workername workerpasswd + subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms + dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + dnf install buildbot-worker -(Note that on Windows, the ``buildbot-worker`` command will be in the -:file:`Scripts` directory of your Python installation.) + **CentOS Stream 9 / 10** (requires CRB + EPEL):: -On Windows, `the maximum length for a path is limited -<https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation>`_. -This might cause some tests to fail, unless long paths support is enabled. + dnf config-manager --set-enabled crb + dnf install epel-release epel-next-release + dnf install buildbot-worker -Use this PowerShell command to check whether long paths are enabled:: + The RPM creates a ``buildbot-worker`` system user, installs a + templated systemd unit ``buildbot-worker@.service``, and creates + ``/var/lib/buildbot/worker/`` as the base directory for worker + instances. + + .. tip:: + + If your system has most of its disk space on ``/home`` rather than + on the root partition, create the worker data under ``/home`` and + symlink it so the packaged systemd unit still works:: + + mkdir -p /home/buildbot-worker/worker + ln -s /home/buildbot-worker/worker /var/lib/buildbot/worker + + Adjust ownership and paths to match your distro's conventions. + + Create the worker (replace ``WORKERNAME`` and ``WORKERPASSWD`` with + the credentials provided to you from your buildmaster-config issue):: + + sudo -u buildbot-worker buildbot-worker create-worker \ + /var/lib/buildbot/worker/WORKERNAME \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD + + Edit ``info/admin``, ``info/host``, and ``buildbot.tac`` in the worker + directory (see below for recommended settings). + + Enable and start the service:: + + systemctl enable --now buildbot-worker@WORKERNAME.service + + .. tab:: Debian / Ubuntu + + :: + + apt install buildbot-worker + + The package creates a ``buildbot`` system user, installs a templated + systemd unit ``buildbot-worker@.service``, and creates + ``/var/lib/buildbot/workers/`` as the base directory for worker + instances. + + .. tip:: + + If your system has most of its disk space on ``/home`` rather than + on the root partition, create the worker data under ``/home`` and + symlink it so the packaged systemd unit still works:: + + mkdir -p /home/buildbot/workers + ln -s /home/buildbot/workers /var/lib/buildbot/workers + + Adjust ownership and paths to match your distro's conventions. + + Create the worker (replace ``WORKERNAME`` and ``WORKERPASSWD`` with + the credentials provided to you from your buildmaster-config issue):: + + sudo -u buildbot buildbot-worker create-worker \ + /var/lib/buildbot/workers/WORKERNAME \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD + + Edit ``info/admin``, ``info/host``, and ``buildbot.tac`` in the worker + directory (see below for recommended settings). + + Enable and start the service:: + + systemctl enable --now buildbot-worker@WORKERNAME.service + + .. tab:: Other / pip + + For distros without a ``buildbot-worker`` package, install via pip:: + + pip install buildbot-worker + + **NixOS** users should use the built-in ``services.buildbot-worker`` + NixOS module; see the + `nixpkgs module source <https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/continuous-integration/buildbot/worker.nix>`__ + for available options. + + **Arch Linux** has buildbot packages in the AUR, but they are + currently unmaintained. Using pip is more reliable. + + pip does **not** create a system user, directories, or service unit. + Set these up manually. On distros with ``useradd``:: + + useradd --system --shell /sbin/nologin \ + --home-dir /var/lib/buildbot/worker --create-home buildbot-worker + + On Alpine Linux (BusyBox):: + + adduser -S -D -H -h /var/lib/buildbot/worker -s /sbin/nologin buildbot-worker + + Then create the directories:: + + mkdir -p /var/lib/buildbot/worker + chown buildbot-worker:buildbot-worker /var/lib/buildbot/worker + + Create the worker (replace ``WORKERNAME`` and ``WORKERPASSWD`` with + the credentials provided to you from your buildmaster-config issue):: + + sudo -u buildbot-worker buildbot-worker create-worker \ + /var/lib/buildbot/worker/WORKERNAME \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD + + Edit ``info/admin``, ``info/host``, and ``buildbot.tac`` in the worker + directory (see below for recommended settings). + + On systemd-based distros, a service unit must also be installed; see + the service management section below. + + +.. tab:: Unix + + .. tab:: FreeBSD + + :: + + pkg install devel/py-buildbot-worker + + The package creates a ``buildbot`` system user, installs an + ``rc.d`` service with profile support, and creates + ``/var/db/buildbot/workers/`` as the base directory for worker + instances. + + Create the worker (replace ``WORKERNAME`` and ``WORKERPASSWD`` with + the credentials provided to you from your buildmaster-config issue):: + + su -m buildbot -c "buildbot-worker create-worker \ + /var/db/buildbot/workers/WORKERNAME \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD" + + Edit ``info/admin``, ``info/host``, and ``buildbot.tac`` in the worker + directory (see below for recommended settings). + + Enable and start the service. The rc.d script uses profile names as + shell variable identifiers, so pick a short name without hyphens + (it does not need to match the worker name):: + + sysrc buildbot_worker_enable=YES + sysrc buildbot_worker_profiles="myworker" + sysrc buildbot_worker_myworker_enable=YES + sysrc buildbot_worker_myworker_basedir=/var/db/buildbot/workers/WORKERNAME + service buildbot-worker start + + .. tab:: OpenBSD + + :: + + pkg_add buildbot-worker + + The package creates a ``_buildslave`` system user, installs an + ``rc.d`` service, and creates ``/var/buildslave/`` as the default + worker directory. + + Create the worker (replace ``WORKERNAME`` and ``WORKERPASSWD`` with + the credentials provided to you from your buildmaster-config issue):: + + su -m _buildslave -c "buildbot-worker create-worker \ + /var/buildslave \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD" + + Edit ``info/admin``, ``info/host``, and ``buildbot.tac`` in the worker + directory (see below for recommended settings). + + Enable and start the service:: + + rcctl enable buildbot_worker + rcctl start buildbot_worker + + The ``rc.d`` script supports a single worker. To run multiple + workers, create each in a subdirectory and point the service flags + at the desired one (or create additional ``rc.d`` scripts):: + + su -m _buildslave -c "buildbot-worker create-worker \ + /var/buildslave/WORKERNAME \ + buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD" + rcctl enable buildbot_worker + rcctl set buildbot_worker flags /var/buildslave/WORKERNAME + rcctl start buildbot_worker + + +.. tab:: macOS + + * Create a buildbot user using the macOS control panel user admin. It + should be a "standard" user. + * Log in as the buildbot user. + * Install the buildbot worker [#]_ by running ``pip install buildbot-worker``. + + In a terminal window for the buildbot user, issue the following commands (you + can put the ``buildarea`` wherever you want to):: + + mkdir buildarea + buildbot-worker create-worker buildarea buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD + + +.. tab:: Windows + + * Create a buildbot user as a "standard" user. + * Install the latest version of Python from python.org. + * Open a Command Prompt. + * Execute ``python -m pip install pywin32 buildbot-worker`` (note that + ``python.exe`` is not added to ``PATH`` by default, making the + ``python`` command accessible is left as an exercise for the user). + + On Windows, `the maximum length for a path is limited + <https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation>`__. + This might cause some tests to fail, unless long paths support is enabled. + + Use this PowerShell command to check whether long paths are enabled:: Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -If the value is not "1", you can enable long paths using this PowerShell command:: + If the value is not "1", you can enable long paths using this PowerShell command:: New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force -Once this initial worker setup completes, you should edit the files -``buildarea/info/admin`` and ``buildarea/info/host`` to provide your contact -info and information on the host configuration, respectively. This information -will be presented in the buildbot web pages that display information about the -builders running on your worker. + + In a terminal window for the buildbot user, issue the following commands. + (You can put the ``buildarea`` wherever you want to.) + Note that the ``buildbot-worker`` command will be in the + :file:`Scripts` directory of your Python installation. Here and in the rest + of the guide, you may need to launch it using the full path. + + .. code-block:: + + mkdir buildarea + buildbot-worker create-worker buildarea buildbot-api.python.org:9020 WORKERNAME WORKERPASSWD + + +The ``info/admin`` file in the worker directory should contain your contact +information, and ``info/host`` should describe the host configuration. This +information is displayed on the buildbot web interface. Since these pages are +publicly visible, consider obfuscating your email address (for example, +``user AT example.com``) to avoid spam from web scrapers. + +The recommended ``buildbot.tac`` settings are: + +* ``keepalive = 60`` -- the buildmaster uses a 60-second keepalive interval; + the default of ``600`` is too high and can cause spurious disconnections. +* ``delete_leftover_dirs = 1`` -- automatically cleans up build directories + that the master no longer needs. + +.. tip:: + + Build directories and ``twistd.log`` rotations can accumulate over time. + Monitor free disk space on the partition that holds the worker directory, + even with ``delete_leftover_dirs`` enabled. + +Service management +~~~~~~~~~~~~~~~~~~ You will also want to make sure that the worker is started when the machine reboots: -For Linux: +.. tab:: Linux + + .. tab:: Distro package + + If you installed via a distro package (Fedora, RHEL, CentOS, Debian, + or Ubuntu), the service was already enabled in the installation + step above. -* For systemd based distributions, you can create a systemd unit file in order - to manage the service. Create the unit file named ``buildbot-worker.service`` - under ``/home/buildbot/.config/systemd/user/`` and change the paths according to where the - buildbot-worker binary resides. You can verify its location by running - ``which buildbot-worker``. - If you installed the buildbot-worker through - your package manager it would be:: - - [Unit] - Description=Buildbot Worker - Wants=network-online.target - After=network-online.target local-fs.target - - [Service] - Type=forking - PIDFile=/home/buildbot/buildarea/twistd.pid - WorkingDirectory=/home/buildbot/buildarea - ExecStart=/usr/bin/buildbot-worker start - ExecReload=/usr/bin/buildbot-worker restart - ExecStop=/usr/bin/buildbot-worker stop - Restart=always - User=buildbot - - [Install] - WantedBy=multi-user.target - - - If you installed the buildbot-worker through pip, the systemd unit - file should look like this:: - - [Unit] - Description=Buildbot Worker - Wants=network-online.target - After=network-online.target local-fs.target - - [Service] - Type=forking - PIDFile=/home/buildbot/buildarea/twistd.pid - WorkingDirectory=/home/buildbot/buildarea - ExecStart=/usr/local/bin/buildbot-worker start - ExecReload=/usr/local/bin/buildbot-worker restart - ExecStop=/usr/local/bin/buildbot-worker stop - Restart=always - User=buildbot - - [Install] - WantedBy=multi-user.target - - - Then enable lingering for the buildbot user via the - ``loginctl enable-linger buildbot`` command and you can start - the service through a login shell of the buildbot user - via the ``systemctl --user enable --now buildbot-worker.service`` - command. - - Note that using a systemd unit file, might produce some selinux warnings on systems - where the enforcing mode is enabled, usually related to the twistd.pid file. - If the service fails to start, you should check the output of - ``systemctl status buildbot-worker.service`` as well as the - ``/var/log/audit/audit.log`` file (e.g. through - ``sealert -a /var/log/audit/audit.log``) for potential issues and remedies. - - -* Alternatively you can create a cronjob. Add the following line to ``/etc/crontab``:: - - @reboot buildbot-worker restart /path/to/buildarea - - Note that we use ``restart`` rather than ``start`` in case a crash has - left a ``twistd.pid`` file behind. - -For OSX: - -* Create a bin directory for your buildbot user:: - - mkdir bin - -* Place the following script, named ``run_worker.sh``, into that directory:: - - #!/bin/bash - export PATH=/usr/local/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH - export LC_CTYPE=en_US.utf-8 - cd /Users/buildbot/buildarea - twistd --nodaemon --python=buildbot.tac --logfile=buildbot.log --prefix=worker - - If you use pip with Apple's system python, add '/System' to the front of - the path to the Python bin directory. - -* Place a file with the following contents into ``/Library/LaunchDaemons``: - - .. code-block:: xml - - <?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" - "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> - <plist version="1.0"> - <dict> - <key>Label</key> - <string>net.buildbot.worker</string> - <key>UserName</key> - <string>buildbot</string> - <key>WorkingDirectory</key> - <string>/Users/buildbot/buildarea</string> - <key>ProgramArguments</key> - <array> - <string>/Users/buildbot/bin/run_worker.sh</string> - </array> - <key>StandardOutPath</key> - <string>twistd.log</string> - <key>StandardErrorPath</key> - <string>twistd.log</string> - <key>KeepAlive</key> - <true/> - <key>SessionCreate</key> - <true/> - </dict> - </plist> + .. tab:: Manual systemd - The recommended name for the file is ``net.buildbot.worker``. + If you installed via pip, you need to install a systemd unit yourself. + The upstream buildbot project provides a + `contributed template unit <https://github.com/buildbot/buildbot/blob/master/worker/contrib/systemd/buildbot-worker%40.service>`__ + along with + `sysusers.d and tmpfiles.d configs <https://github.com/buildbot/buildbot/tree/master/common/contrib/systemd>`__. -For Windows: + Create ``/etc/systemd/system/buildbot-worker@.service`` with the + following contents:: -* Add a Scheduled Task to run ``buildbot-worker start buildarea`` as the - buildbot user "when the computer starts up". It is best to provide - absolute paths to the ``buildbot-worker`` command and the :file:`buildarea` - directory. It is also recommended to set the task to run in the - directory that contains the :file:`buildarea` directory. + [Unit] + Description=Buildbot Worker %i + Documentation=man:buildbot-worker(1) https://docs.buildbot.net/ + After=network.target + ConditionDirectoryNotEmpty=/var/lib/buildbot/worker/%i + ConditionFileNotEmpty=/var/lib/buildbot/worker/%i/buildbot.tac -* Alternatively (note: don't do both!), set up the worker - service as described in the `buildbot documentation - <https://docs.buildbot.net/current/manual/installation/misc.html#launching-worker-as-windows-service>`_. - -To start the worker running for your initial testing, you can do:: + [Service] + Type=simple + User=buildbot-worker + Group=buildbot-worker + WorkingDirectory=/var/lib/buildbot/worker/ + StateDirectory=buildbot/worker + ExecStart=/usr/local/bin/buildbot-worker start --nodaemon %i + Restart=always + ProtectSystem=full + ProtectHome=yes + PrivateDevices=yes + PrivateTmp=yes - buildbot-worker start buildarea + [Install] + WantedBy=multi-user.target + + Adjust ``User``, ``Group``, ``WorkingDirectory``, and the + ``ExecStart`` path to match your setup. If your worker data is + symlinked from ``/home`` (see the filesystem layout tip above), + change ``ProtectHome=yes`` to ``ProtectHome=no`` so systemd can + follow the symlink. Then:: + + systemctl daemon-reload + systemctl enable --now buildbot-worker@WORKERNAME.service + + .. tab:: SysV init + + For distros without systemd (such as Alpine Linux with OpenRC), + upstream provides a + `SysV init script <https://github.com/buildbot/buildbot/blob/master/worker/contrib/init-scripts/buildbot-worker.init.sh>`__ + with a + `default configuration file <https://github.com/buildbot/buildbot/blob/master/worker/contrib/init-scripts/buildbot-worker.default>`__. + Install these as ``/etc/init.d/buildbot-worker`` and + ``/etc/default/buildbot-worker`` respectively, then configure the + worker instances in the default file. + + .. tab:: cron job + + If neither systemd nor a SysV init script is practical, you can use + a cron job. Add the following line to ``/etc/crontab``:: + + @reboot buildbot-worker restart /path/to/workerdir + + Note that ``restart`` is used rather than ``start`` in case a crash + has left a ``twistd.pid`` file behind. + +.. tab:: Unix + + If you installed via a package on FreeBSD or OpenBSD, the service + was already enabled in the installation step above. To manage it + manually: + + On FreeBSD:: + + service buildbot-worker status + service buildbot-worker restart + + On OpenBSD:: + + rcctl check buildbot_worker + rcctl restart buildbot_worker + + If you installed via pip, you will need to write an ``rc.d`` script + or use the cron job approach described in the Linux tab. + +.. tab:: macOS + + * Create a bin directory for your buildbot user:: + + mkdir bin + + * Place the following script, named ``run_worker.sh``, into that directory:: + + #!/bin/bash + export PATH=/usr/local/bin:/Library/Frameworks/Python.framework/Versions/Current/bin:$PATH + export LC_CTYPE=en_US.utf-8 + cd /Users/buildbot/buildarea + twistd --nodaemon --python=buildbot.tac --logfile=buildbot.log --prefix=worker + + * Place a file with the following contents into ``/Library/LaunchDaemons``: + + .. code-block:: xml + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> + <plist version="1.0"> + <dict> + <key>Label</key> + <string>net.buildbot.worker</string> + <key>UserName</key> + <string>buildbot</string> + <key>WorkingDirectory</key> + <string>/Users/buildbot/buildarea</string> + <key>ProgramArguments</key> + <array> + <string>/Users/buildbot/bin/run_worker.sh</string> + </array> + <key>StandardOutPath</key> + <string>twistd.log</string> + <key>StandardErrorPath</key> + <string>twistd.log</string> + <key>KeepAlive</key> + <true/> + <key>SessionCreate</key> + <true/> + </dict> + </plist> + + The recommended name for the file is ``net.buildbot.worker``. + +.. tab:: Windows + + * Add a Scheduled Task to run ``buildbot-worker start buildarea`` as the + buildbot user "when the computer starts up". It is best to provide + absolute paths to the ``buildbot-worker`` command and the :file:`buildarea` + directory. It is also recommended to set the task to run in the + directory that contains the :file:`buildarea` directory. + + * Alternatively (note: don't do both!), set up the worker + service as described in the `buildbot documentation + <https://docs.buildbot.net/current/manual/installation/misc.html#launching-worker-as-windows-service>`__. + +If you have not already started the worker through a service manager, you +can start it manually for initial testing:: + + buildbot-worker start /path/to/workerdir Then you can either wait for someone to make a commit, or you can pick a builder associated with your worker from the `list of builders -<https://buildbot.python.org/all/>`_ and force a build. +<builders_>`__ and force a build. In any case you should initially monitor builds on your builders to make sure the tests are passing and to resolve any platform issues that may be revealed @@ -270,19 +512,13 @@ by tests that fail. Unfortunately we do not currently have a way to notify you only of failures on your builders, so doing periodic spot checks is also a good idea. -.. note:: - If your buildbot worker is disconnecting regularly, it may be a symptom of the - default ``keepalive`` value (``600`` for 10 minutes) being `set - <https://docs.buildbot.net/latest/manual/installation/worker.html#cmdoption-buildbot-worker-create-worker-keepalive>`_ - too high. You can change it to a lower value (for example, ``180`` for 3 minutes) - in the ``buildbot.tac`` file found in your build area. - +---- Latent workers -------------- We also support running `latent workers -<https://docs.buildbot.net/current/manual/configuration/workers.html#latent-workers>`_ +<https://docs.buildbot.net/current/manual/configuration/workers.html#latent-workers>`__ on the AWS EC2 service. To set up such a worker: * Start an instance of your chosen base AMI and set it up as a @@ -305,7 +541,7 @@ instance(s), so it is recommended to periodically check and make sure there are no "zombie" instances running on your account, created by the buildbot master. Also, if you notice that your worker seems to have been down for an unexpectedly long time, please ping the `python-buildbots -<https://mail.python.org/mailman3/lists/python-buildbots.python.org/>`_ list to +<https://mail.python.org/mailman3/lists/python-buildbots.python.org/>`__ list to request that the master be restarted. Latent workers should also be updated periodically to include operating system @@ -339,7 +575,7 @@ Necessary tasks include, obviously, keeping the buildbot running. Currently the system for notifying buildbot owners when their workers go offline is not working; this is something we hope to resolve. So currently it is helpful if you periodically check the status of your worker. We will also contact you -via your contact address in ``buildarea/info/admin`` when we notice there is a +via your contact address in ``info/admin`` when we notice there is a problem that has not been resolved for some period of time and you have not responded to a posting on the python-buildbots list about it. @@ -368,19 +604,19 @@ a table listing all of the outbound ports used by the buildbot and the python test suite (this list may not be complete as new tests may have been added since this table was last vetted): -======= =================== ================================================ -Port Host Description -======= =================== ================================================ -20, 21 ftp.debian.org test_urllib2net -53 your DNS server test_socket, and others implicitly -80 python.org (several tests) +======= ========================== ================================================ +Port Host Description +======= ========================== ================================================ +20, 21 ftp.debian.org test_urllib2net +53 your DNS server test_socket, and others implicitly +80 python.org (several tests) example.com -119 news.gmane.org test_nntplib -443 (various) test_ssl -465 smtp.gmail.com test_smtpnet -587 smtp.gmail.com test_smtpnet -9020 python.org connection to buildmaster -======= =================== ================================================ +119 news.gmane.org test_nntplib (Python versions < 3.13) +443 (various) test_ssl +465 smtp.gmail.com test_smtpnet +587 smtp.gmail.com test_smtpnet +9020 buildbot-api.python.org connection to buildmaster +======= ========================== ================================================ Many tests will also create local TCP sockets and connect to them, usually using either ``localhost`` or ``127.0.0.1``. @@ -390,7 +626,7 @@ Required resources ================== Based on the last time we did a `survey -<https://mail.python.org/pipermail/python-dev/2012-March/117978.html>`_ on +<https://mail.python.org/pipermail/python-dev/2012-March/117978.html>`__ on buildbot requirements, the recommended resource allocations for a python buildbot are at least: @@ -398,22 +634,22 @@ buildbot are at least: * 512 MB RAM * 30 GB free disk space -The bigmem tests won't run in this configuration, since they require -substantially more memory, but these resources should be sufficient to ensure -that Python compiles correctly on the platform and can run the rest of the test -suite. +Many tests won't run in this configuration, since they require +substantially more memory, but these resources should be sufficient. +Builders with minimal settings might need more maintenance: they check +that Python's resource-hungry tests are tagged and skipped correctly. Security considerations ======================= We only allow builds to be triggered against commits to the -`CPython repository on GitHub <https://github.com/python/cpython>`_. +`CPython repository on GitHub <https://github.com/python/cpython>`__. This means that the code your buildbot will run will have been vetted by a committer. However, mistakes and bugs happen, as could a compromise, so keep this in mind when siting your buildbot on your network and establishing the security around it. Treat the buildbot like you would any resource that is public facing and might -get hacked (use a VM and/or jail/chroot/solaris zone, put it in a DMZ, etc). +get hacked (use a VM and/or jail/chroot/solaris zone, put it in a DMZ, and so on). While the buildbot does not have any ports open for inbound traffic (and is not public facing in that sense), committer mistakes do happen, and security flaws are discovered in both released and unreleased code, so treating the buildbot @@ -422,12 +658,12 @@ as if it were fully public facing is a good policy. Code runs differently as privileged and unprivileged users. We would love to have builders running as privileged accounts, but security considerations do make that difficult, as access to root can provide access to surprising -resources (such as spoofed IP packets, changes in MAC addresses, etc) even on a +resources (such as spoofed IP packets, changes in MAC addresses, and so on) even on a VM setup. But if you are confident in your setup, we'd love to have a buildbot that runs python as root. Note that the above is a summary of a `discussion -<https://mail.python.org/pipermail/python-dev/2011-October/113935.html>`_ on +<https://mail.python.org/pipermail/python-dev/2011-October/113935.html>`__ on python-dev about buildbot security that includes examples of the tests for which privilege matters. There was no final consensus, but the information is useful as a point of reference. @@ -435,3 +671,5 @@ useful as a point of reference. .. [#] If the buildbot is going to do Framework builds, it is better to use the Apple-shipped Python so as to avoid any chance of the buildbot picking up components from the installed python.org python. + +.. _builders: https://buildbot.python.org/#/builders diff --git a/testing/run-write-tests.rst b/testing/run-write-tests.rst index 83a4a28610..405d10f039 100644 --- a/testing/run-write-tests.rst +++ b/testing/run-write-tests.rst @@ -5,13 +5,7 @@ Running and writing tests ========================= -.. raw:: html - - <script> - document.addEventListener('DOMContentLoaded', function() { - activateTab(getOS()); - }); - </script> +.. include:: /include/activate-tab.rst .. note:: @@ -286,7 +280,7 @@ Benchmarks Benchmarking is useful to test that a change does not degrade performance. -`The Python Benchmark Suite <https://github.com/python/pyperformance>`_ +`The Python Benchmark Suite <https://github.com/python/pyperformance>`__ has a collection of benchmarks for all Python implementations. Documentation about running the benchmarks is in the `README.txt -<https://github.com/python/pyperformance/blob/main/README.rst>`_ of the repo. +<https://github.com/python/pyperformance/blob/main/README.rst>`__ of the repo. diff --git a/triage/github-bpo-faq.rst b/triage/github-bpo-faq.rst index 8c21a17fea..f4f8b16dd4 100644 --- a/triage/github-bpo-faq.rst +++ b/triage/github-bpo-faq.rst @@ -16,7 +16,7 @@ How to format my comments nicely? ================================= There is a wonderful `beginner guide to writing and formatting on GitHub -<https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github>`_. +<https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github>`__. Highly recommended. One pro-tip we can sell you right here is that if you want to paste @@ -43,7 +43,7 @@ Use Markdown links. If you link to the default GitHub path, the file will link to the latest current version on the given branch. You can get a permanent link to a given revision of a given file by -`pressing "y" <https://docs.github.com/en/repositories/working-with-files/using-files/getting-permanent-links-to-files>`_. +`pressing "y" <https://docs.github.com/en/repositories/working-with-files/using-files/getting-permanent-links-to-files>`__. How to do advanced searches? ============================ @@ -80,7 +80,7 @@ Add a checkbox list like this in the issue description:: then those will become sub-tasks on the given issue. Moreover, GitHub will automatically mark a task as complete if the other referenced issue is closed. More details in the `official GitHub documentation -<https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/about-task-lists>`_. +<https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/about-task-lists>`__. What on earth is a "mannequin"? =============================== @@ -88,7 +88,7 @@ What on earth is a "mannequin"? For issues migrated to GitHub from `bpo`_ where the authors or commenters are not core developers, we opted not to link to their GitHub accounts directly. Users not in the `python organization on GitHub -<https://github.com/orgs/python/people>`_ might not like comments to +<https://github.com/orgs/python/people>`__ might not like comments to appear under their name from an automated import. Others never linked GitHub on `bpo`_ in the first place so linking their account, if any, would be impossible. diff --git a/triage/issue-tracker.rst b/triage/issue-tracker.rst index b311a51a74..4dd0815e4c 100644 --- a/triage/issue-tracker.rst +++ b/triage/issue-tracker.rst @@ -57,10 +57,10 @@ will ask you to do so now. First you need to select what kind of problem you want to report. The available choices include, for example: - * **Bug report**: an existing feature isn't working as expected. - * **Documentation**: there is missing, invalid, or misleading documentation. - * **Feature or enhancement**: suggest a new feature for Python. - * **Report a security vulnerability**: privately report a security vulnerability. +* **Bug report**: an existing feature isn't working as expected. +* **Documentation**: there is missing, invalid, or misleading documentation. +* **Feature or enhancement**: suggest a new feature for Python. +* **Report a security vulnerability**: privately report a security vulnerability. Depending on your choice, a dedicated form template will appear. In particular, you'll notice that the last button actually takes you to diff --git a/triage/labels.rst b/triage/labels.rst index d78f6b4727..96e0d8f58e 100644 --- a/triage/labels.rst +++ b/triage/labels.rst @@ -9,7 +9,7 @@ Triagers, core developers and bots can add labels on GitHub to categorize issues and pull requests. Many labels are shared for both use cases, while some are dedicated only to one. Below is a possibly inexhaustive list, but it should get -you going. For a full list, see `here <https://github.com/python/cpython/issues/labels>`_. +you going. For a full list, see `here <https://github.com/python/cpython/issues/labels>`__. .. _general-purpose-labels: @@ -30,6 +30,8 @@ These labels are used to specify the type of issue: it is implicit that features are added to the ``main`` branch only. The `Ideas Discourse category`_ can be used to discuss enhancements before filing an issue. +* :gh-label:`type-refactor`: for general code refactoring that + does not change user-facing behaviour. * :gh-label:`type-security`: for security issues. See also `Reporting security issues in Python`_. @@ -41,7 +43,7 @@ Component labels ================ These labels are mostly used to specify which :ref:`part of the codebase -<build-directory-structure>` is affected by the issue/PR: +<build_directory_structure>` is affected by the issue/PR: * :gh-label:`stdlib`: for standard library modules in the :cpy-file:`Lib` directory (written in Python). @@ -71,7 +73,7 @@ we don't have a dedicated Unix label. Use the :gh-label:`OS-unsupported` label for issues on platforms outside the support tiers defined in :pep:`11`. Applying this label adds the issue to -`a GitHub project <https://github.com/orgs/python/projects/27/views/1>`_ where +`a GitHub project <https://github.com/orgs/python/projects/27/views/1>`__ where it can be categorized further. See also the :ref:`Platform experts list <platform-experts>`. @@ -90,7 +92,7 @@ they are encouraged to subscribe to them. Depending on the label, this might also automatically add the issue to a GitHub project. You can see the `full list of topic labels on GitHub -<https://github.com/python/cpython/labels?q=topic>`_. +<https://github.com/python/cpython/labels?q=topic>`__. .. _Version labels: @@ -122,15 +124,15 @@ Other labels * :gh-label:`pending`: for issues/PRs that will be closed unless further feedback is provided. * :gh-label:`release-blocker`/:gh-label:`deferred-blocker`: for issues/PRs - and the :ref:`branch's release manager <branchstatus>` - removing or retaining the label as appropriate. that, unless fixed, will hold the current or next release respectively. Triagers may set these labels for issues that must be fixed before a release, + and the :ref:`branch's release manager <branchstatus>` will review them and determine if they indeed qualify, + removing or retaining the label as appropriate. * :gh-label:`sprint`: for easier filtering of issues/PRs being worked on during official sprints. * :gh-label:`stale`: for issues/PRs that have been inactive for a while. -* :gh-label:`triaged`: for issue has been accepted as valid by a triager. +* :gh-label:`triaged`: for issues that have been accepted as valid by a triager. .. _GitHub Labels for PRs: @@ -158,9 +160,13 @@ to trigger specific bot behaviors. * :gh-label:`skip news <skip%20news>`: for PRs that don't need a NEWS entry. The :ref:`news-entry` section covers in details in which cases the NEWS entry can be skipped. -* :gh-label:`test-with-buildbots`: used to test the latest commit with - the :ref:`buildbot fleet <buildbots>` whenever more testing is required - before merging. This may take multiple hours to complete. +* :gh-label:`🔨 test-with-buildbots <%3Ahammer%3A%20test-with-buildbots>`: used + to test the latest commit with the :ref:`buildbot fleet <buildbots>` whenever + more testing is required before merging. This may take multiple hours to + complete. +* :gh-label:`🔨 test-with-refleak-buildbots <%3Ahammer%3A%20test-with-refleak-buildbots>`: + Run the reference leak buildbots on the latest commit. Useful for when the + code might be leaky. * :samp:`awaiting {action}`: these labels are applied and used by `bedevere`_ to indicate the stage of a PR and should not be applied manually. diff --git a/triage/triage-team.rst b/triage/triage-team.rst index 68a88457e4..7acebc130c 100644 --- a/triage/triage-team.rst +++ b/triage/triage-team.rst @@ -86,14 +86,14 @@ Any existing active contributor to the Python repository on GitHub can transition into becoming a Python triager. They can request this to any core developer, either confidentially via a DM in Discourse, or publicly by opening an `issue in the core-workflow repository -<https://github.com/python/core-workflow/issues/new?template=triage_membership.md>`_. +<https://github.com/python/core-workflow/issues/new?template=triage_membership.md>`__. If the core developer decides you are ready to gain the extra privileges on the tracker, they will ask a :ref:`Python organization admin <current owners>` to invite you to the Python organisation, and then act as a mentor to you until you are ready to do things entirely on your own. For every new triager, it would be great to announce them in the -`Committers category <https://discuss.python.org/c/committers/5>`_ -on the `Python Discourse <https://discuss.python.org/>`_ +`Committers category <https://discuss.python.org/c/committers/5>`__ +on the `Python Discourse <https://discuss.python.org/>`__ (`example announcement <https://discuss.python.org/t/abhilash-raj-has-been-granted-triage-role-on-github/2089>`__). diff --git a/triage/triaging.rst b/triage/triaging.rst index c560d8c1d5..207c59082f 100644 --- a/triage/triaging.rst +++ b/triage/triaging.rst @@ -92,7 +92,6 @@ you can help by making sure the pull request: * includes proper tests * includes proper documentation changes * includes a :ref:`NEWS entry <news-entry>` (if needed) -* includes the author in ``Misc/ACKS``, either already or the pull request adds them * doesn't have conflicts with the ``main`` branch * :ref:`doesn't have failing CI checks <keeping-ci-green>` diff --git a/versions.rst b/versions.rst index db7f946829..3d5fdced91 100644 --- a/versions.rst +++ b/versions.rst @@ -5,18 +5,17 @@ Status of Python versions ========================= -The ``main`` branch is currently the future Python 3.14, and is the only +The ``main`` branch is currently the future Python |main_version|, and is the only branch that accepts new features. The latest release for each Python -version can be found on the `download page <https://www.python.org/downloads/>`_. +version can be found on the `download page <https://www.python.org/downloads/>`__. -Python release cycle -==================== - .. raw:: html - :file: include/release-cycle.svg + :file: _static/release-cycle.svg + +(See :ref:`below <full-chart>` for a chart with older versions. +Another useful visualization is `endoflife.date/python <https://endoflife.date/python>`__.) -Another useful visualization is `endoflife.date/python <https://endoflife.date/python>`_. Supported versions ================== @@ -37,23 +36,40 @@ Unsupported versions .. csv-table:: :header-rows: 1 :width: 100% - :file: include/end-of-life.csv + :file: _static/end-of-life.csv + + +.. _full-chart: + +Full chart +========== + +.. raw:: html + :file: _static/release-cycle-all.svg Status key ========== -:feature: new features, bugfixes, and security fixes are accepted. -:prerelease: feature fixes, bugfixes, and security fixes are accepted for the - upcoming feature release. -:bugfix: bugfixes and security fixes are accepted, new binaries are still - released. (Also called **maintenance** mode or **stable** release) -:security: only security fixes are accepted and no more binaries are released, - but new source-only versions can be released -:end-of-life: release cycle is frozen; no further changes can be pushed to it. +Python releases go through five phases, as described in :pep:`602`. Release +managers can adjust specific dates as needed. -See also the :ref:`devcycle` page for more information about branches and backporting. +:feature: Before the first beta, the next full release can accept new features, + bug fixes, and security fixes. + +:prerelease: After the first beta, no new features can go in, but feature fixes + (including significant changes to new features), bug fixes, and security fixes + are accepted for the upcoming feature release. + +:bugfix: Once a version has been fully released, bug fixes and security fixes are + accepted. New binaries are built and released roughly every two months. This + phase is also called **maintenance** mode or **stable** release. -By default, the end-of-life is scheduled 5 years after the first release, -but can be adjusted by the release manager of each branch. All Python 2 -versions have reached end-of-life. +:security: After two years (18 months for versions before 3.13), only security + fixes are accepted and no more binaries are released. New source-only versions + can be released as needed. + +:end-of-life: Five years after a release, support ends. The release cycle is + frozen; no further changes are allowed. + +See also the :ref:`devcycle` page for more information about branches and backporting.