# python-patterns Admin & Contributor Guide

This guide is for maintainers, contributors, and architects working *on* the `python-patterns` repository — as opposed to developers simply reading the patterns (covered in the User Guide). It documents how the collection is structured, how its self-testing machinery works, the toolchain and CI that keep it consistent, the contribution contract, and the known issues and improvement opportunities surfaced by the project's own issue tracker.

---

## 1. Executive Summary

`python-patterns` is a **teaching catalog**, not a deployable application or a published library. Its "product" is a set of ~33 self-contained Python files, each demonstrating one design pattern or idiom, grouped by the classic Gang of Four taxonomy plus a few project-specific categories.

| Aspect | Reality |
|---|---|
| **What it is** | A curated reference collection of design-pattern implementations in Python |
| **What it is not** | Not a service, not a CLI tool, not an importable dependency library |
| **Runtime dependencies** | None — every pattern is standard-library only |
| **The "build" output** | There is none; the source files *are* the deliverable |
| **The "tests"** | Embedded doctests in every pattern file, plus a parallel `tests/` suite of pytest unit tests |
| **Quality gates** | `black`, `isort`, `flake8`, `mypy`, `pyupgrade`, `codespell`, run via `tox` and Travis CI |
| **Supported Python** | 3.10 – 3.13 (`requires-python = ">=3.10"`) |
| **License** | None declared in this revision (see §11 Known Issues — this is an open tracker item) |

> [!IMPORTANT]
> Because there is no service and no published package, the operational concerns here are entirely about **repository hygiene**: keeping every pattern consistent in style, ensuring every documented example actually runs, and managing contributions. There is nothing to deploy, monitor, scale, or secure at runtime. This guide reframes the usual "deployment / operations" chapters accordingly.

---

## 2. Architecture

The repository has two architectures worth understanding: the **content taxonomy** (how patterns are organized) and the **self-verification architecture** (how every example stays correct).

### 2.1 Content taxonomy

```text
patterns/
├── creational/      7 patterns — object creation
│   ├── abstract_factory.py  borg.py  builder.py  factory.py
│   ├── lazy_evaluation.py    pool.py  prototype.py
│   └── viz/                  rendered .png class diagrams (one per pattern)
├── structural/      10 patterns — object/class composition
│   ├── 3-tier.py  adapter.py  bridge.py  composite.py  decorator.py
│   ├── facade.py  flyweight.py  flyweight_with_metaclass.py
│   ├── front_controller.py  mvc.py  proxy.py
│   └── viz/
├── behavioral/      17 patterns — communication & responsibility
│   ├── catalog.py  chain_of_responsibility.py  chaining_method.py
│   ├── command.py  iterator.py  iterator_alt.py  mediator.py
│   ├── memento.py  observer.py  publish_subscribe.py  registry.py
│   ├── servant.py  specification.py  state.py  strategy.py
│   ├── template.py  visitor.py
│   └── viz/
├── fundamental/     1 pattern — foundational idioms
│   └── delegation_pattern.py
├── other/           3 non-GoF patterns
│   ├── blackboard.py  graph_search.py
│   └── hsm/hsm.py   (hierarchical state machine + its own exceptions)
├── dependency_injection.py   design-for-testability (3 variants)
└── __init__.py
```

Each `viz/` subfolder holds pre-rendered `*.py.png` class diagrams (one per pattern) used by the README. These are generated artifacts, not source.

> [!NOTE]
> The taxonomy is deliberately the *same* one the Gang of Four book uses, so the repository doubles as a navigable index into that canon. The `fundamental`, design-for-testability (`dependency_injection.py`), and `other` buckets extend it with idioms the GoF set does not cover.

### 2.2 Self-verification architecture — the core design decision

The single most important architectural choice in this repository is that **every pattern file is its own test**. There is no separate "examples vs. tests" split for the demonstration code; the demonstration *is* a test.

```text
┌─────────────────────────────────────────────┐
│  patterns/<category>/<name>.py               │
│                                              │
│  """module docstring — the WHY + trade-offs"""│
│                                              │
│  class / function implementations            │
│                                              │
│  def main():                                 │
│      """                                     │
│      >>> usage example                       │   ← doctest: doc + example + test
│      expected output                         │
│      """                                     │
│                                              │
│  if __name__ == "__main__":                  │
│      import doctest                           │
│      doctest.testmod()                       │   ← runs the doctest on execution
└─────────────────────────────────────────────┘
            │                        │
            ▼                        ▼
   python <file>.py          pytest --doctest-modules patterns/
   (runs that file's          (discovers and runs EVERY pattern's
    doctest, silent on         doctest in one pass)
    success)
```

In parallel, a conventional unit-test suite mirrors the pattern tree:

```text
tests/
├── behavioral/    test_catalog.py, test_mediator.py, test_memento.py,
│                  test_observer.py, test_publish_subscribe.py, test_servant.py,
│                  test_state.py, test_strategy.py, test_visitor.py
├── creational/    test_abstract_factory.py, test_borg.py, test_builder.py,
│                  test_factory.py, test_lazy.py, test_pool.py, test_prototype.py
├── structural/    test_adapter.py, test_bridge.py, test_decorator.py,
│                  test_facade.py, test_flyweight.py, test_mvc.py, test_proxy.py
├── fundamental/   test_delegation.py
└── test_hsm.py
```

> [!IMPORTANT]
> Two test surfaces coexist: **doctests inside `patterns/`** (which verify the documented usage examples) and **pytest unit tests inside `tests/`** (which verify behavior more rigorously). The `pyproject.toml` `addopts` wires both together with `--doctest-modules`. When you change a pattern, you may have to update *both* the in-file docstring and the matching `tests/` file.

### 2.3 Negative space — what the architecture intentionally omits

- **No runtime dependencies.** `pyproject.toml`'s `dependencies` array is empty. This is a hard design constraint: every pattern must work on a clean standard-library Python so it can be copied out in isolation.
- **No Singleton, God Object, or deep-inheritance examples.** These are listed in the README as anti-patterns and are deliberately *not* implemented.
- **No `interpreter.py`.** Although an "interpreter" row appears in the README's behavioral table, no such file exists in this revision (commit `74151cf`). Treat the on-disk file tree, not the README table, as the source of truth for what exists.
- **No build/packaging output.** There is no `dist/`, no wheel pipeline intended for PyPI distribution; the editable install exists only to support testing.

---

## 3. System Requirements

| Component | Requirement | Source of truth |
|---|---|---|
| Python | `>=3.10` (CI runs 3.12) | `pyproject.toml` `requires-python`; `.travis.yml` `python: "3.12"` |
| Standard library only | No runtime deps | `pyproject.toml` `dependencies = []` |
| Git | For cloning / `legacy` tag access | README |
| Dev toolchain | `mypy`, `pyupgrade`, `pytest>=6.2.0`, `pytest-cov>=2.11.0`, `pytest-randomly>=3.1.0`, `black>=25.1.0`, `build>=1.2.2`, `isort>=5.7.0`, `flake8>=7.1.0`, `tox>=4.25.0`, `pipx>=1.7.1` | `pyproject.toml` `[project.optional-dependencies].dev` |

> [!NOTE]
> The `requirements-dev.txt` file lists the dev tools unpinned (`flake8`, `black`, `isort`, `pytest`, `pytest-randomly`, `mypy`, `pyupgrade`, `tox`). The authoritative *pinned* versions live in `pyproject.toml`'s `dev` extra. When the two drift, prefer `pyproject.toml`.

---

## 4. Development Environment Setup

```bash
git clone https://github.com/faif/python-patterns.git
cd python-patterns
python -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate
python -m pip install -e ".[dev]"
```

- [ ] Python 3.10+ active (`python --version`)
- [ ] Virtual environment created and activated
- [ ] `pip install -e ".[dev]"` completed without errors
- [ ] `pytest` runs green
- [ ] `./lint.sh` runs clean (bash-compatible shell)

> [!WARNING]
> The `Makefile` targets (`make pyupgrade`, `make pylinter`) assume an **embedded `venv`** at `./venv`, not a virtualenv elsewhere — the `checkvenv` target hard-fails if `$VIRTUAL_ENV` is unset, and `pyupgrade` looks for `venv/bin/pip-compile`. Create the venv exactly as `python -m venv venv` for the Makefile to work as written.

---

## 5. Testing

### 5.1 Test configuration

The pytest configuration lives in `pyproject.toml` under `[tool.pytest.ini_options]`:

```toml
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
addopts = "--doctest-modules --randomly-seed=1234 --cov=patterns --cov-report=term-missing"
doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"]
log_level = "INFO"
```

Key points:

- `--doctest-modules` makes pytest collect and run the doctests embedded in the pattern files, in addition to the `tests/` unit tests.
- `--randomly-seed=1234` (from `pytest-randomly`) fixes the test execution order so randomized ordering is reproducible.
- `--cov=patterns` produces a coverage report for the `patterns/` package, with missing lines listed in the terminal.
- `doctest_optionflags` enables `ELLIPSIS` (so `...` matches variable output like memory addresses) and `NORMALIZE_WHITESPACE`.

> [!NOTE]
> A second, minimal pytest config exists at `pytest_local.ini` (`addopts = -q`, `testpaths = tests`). It is a lightweight local override for running just the unit tests quietly, without coverage or doctest collection.

### 5.2 Running the tests

=== "Everything (coverage + doctests)"

    ```bash
    pytest
    ```

=== "Just the unit tests, quietly"

    ```bash
    pytest -c pytest_local.ini
    ```

=== "Just the in-file doctests"

    ```bash
    pytest --doctest-modules patterns/
    ```

=== "A single pattern's doctest, verbose"

    ```bash
    python -m doctest -v patterns/creational/factory.py
    ```

### 5.3 Coverage configuration

`[tool.coverage.*]` in `pyproject.toml` enables branch coverage with a per-test dynamic context and excludes boilerplate lines from the report:

```toml
[tool.coverage.run]
branch = true
source = ["./"]
relative_files = true
parallel = true
dynamic_context = "test_function"

[tool.coverage.report]
exclude_lines = [
    "def __repr__", "if self\\.debug", "raise AssertionError",
    "raise NotImplementedError", "if 0:",
    "if __name__ == .__main__.:", "@(abc\\.)?abstractmethod",
]
```

> [!TIP]
> The `exclude_lines` patterns mean abstract methods, `__repr__`, and the `__main__` guards do not count against coverage — so a green coverage report reflects the *pattern logic*, not the scaffolding around it. An HTML report is configured to land in `coverage_html_report/`.

---

## 6. Quality Toolchain & CI

### 6.1 The linting pipeline

The canonical lint sequence is captured in `lint.sh`:

```bash
codespell --quiet-level=2 ./patterns       # spelling
flake8 ./patterns --count --show-source --statistics
isort --profile black ./patterns           # import ordering
tox                                         # tests across env
mypy --ignore-missing-imports ./patterns || true
pytest ./patterns
pytest --doctest-modules ./patterns || true
shopt -s globstar && pyupgrade --py312-plus ./patterns/*.py
```

| Tool | Role | Config location |
|---|---|---|
| `black` | Code formatting (line length 88 via Makefile) | invoked directly / `make pylinter` |
| `isort` | Import sorting, `--profile black` | `lint.sh`, Makefile |
| `flake8` | Linting | `[tool.flake8]` in `pyproject.toml`: `max-line-length = 120`, `ignore = ["E266","E731","W503"]`, `exclude = ["venv*"]` |
| `mypy` | Static type checking | `[tool.mypy]`: `python_version = "3.12"`, `ignore_missing_imports = true` |
| `pyupgrade` | Modernize syntax to `--py312-plus` | `lint.sh`, Makefile |
| `codespell` | Catch typos | `.codespellignore` |

> [!CAUTION]
> There are **two different flake8 line-length settings** in play. `pyproject.toml`'s `[tool.flake8]` sets `max-line-length = 120`, while the `Makefile`'s `pylinter` target passes `--max-line-length 88` (matching black's default) with a broader `--select/--ignore` set. The `Makefile` path is the stricter one. When reconciling lint failures, know which entry point produced them.

### 6.2 Continuous integration

CI runs on **Travis CI** (`.travis.yml`):

```yaml
os: linux
dist: noble
language: python
jobs:
  include:
    - python: "3.12"
      env: TOXENV=py312
install:
  - pip install codecov tox
script:
  - tox
after_success:
  - codecov
```

The pipeline installs `tox` + `codecov`, runs `tox`, and uploads coverage to Codecov on success.

### 6.3 tox

`tox` configuration lives inline in `pyproject.toml` under `[tool.tox]` as `legacy_tox_ini`:

```ini
[tox]
envlist = py312,cov-report
skip_missing_interpreters = true
usedevelop = true
```

> [!NOTE]
> Most of the per-environment `tox` command detail (the `[testenv]` and `[testenv:cov-report]` blocks) is **commented out** in the current `legacy_tox_ini`. The active configuration declares the `py312` and `cov-report` environments with `usedevelop = true` (editable install) and `skip_missing_interpreters = true`. If you are revamping CI, this commented block is the historical reference for what the full matrix used to run (`flake8`, `coverage run -m pytest --doctest-modules`, then a combined coverage report).

---

## 7. Module & Pattern Reference (selected internals)

Rather than re-document every pattern (the User Guide catalogs all of them), this section highlights the implementations whose *internals* are notable for a maintainer.

| Pattern | Internal technique worth knowing |
|---|---|
| `creational/borg.py` | Reassigns `self.__dict__` to a class-level `_shared_state` dict — the entire Monostate trick is one line in `__init__` |
| `creational/lazy_evaluation.py` | Two caching strategies: a descriptor (`lazy_property.__get__`) and a decorator (`lazy_property2`) that stash the result in the instance `__dict__` / a `_lazy__<name>` attribute |
| `structural/flyweight.py` | Pools instances in a `weakref.WeakValueDictionary` keyed by `value+suit`, overriding `__new__` (not `__init__`) |
| `structural/flyweight_with_metaclass.py` | Same pooling via a `FlyweightMeta(type)` metaclass intercepting `__call__`; verified by `assert`s, not a doctest |
| `behavioral/registry.py` | A `RegistryHolder(type)` metaclass auto-registers every subclass in a shared `REGISTRY` dict at class-creation time |
| `behavioral/memento.py` | A `memento()` closure snapshots `obj.__dict__`; the `@Transactional` descriptor rolls back on exception |
| `behavioral/strategy.py` | Uses a **descriptor** (`DiscountStrategyValidator`) with `__set_name__`/`__set__`/`__get__` to validate the injected strategy |
| `behavioral/visitor.py` | Dispatches by walking `node.__class__.__mro__` to find a `visit_<ClassName>` method, falling back to `generic_visit` |
| `structural/mvc.py` | The only file with a substantive executable `__main__` — a `Router` plus `sys.argv`-driven command dispatch |
| `other/hsm/hsm.py` | A nested FSM with four states and its own exception hierarchy (`UnsupportedMessageType`, `UnsupportedState`, `UnsupportedTransition`) |

> [!TIP]
> Several patterns lean on Python's data-model hooks (`__new__`, `__getattr__`, `__get__`/`__set__`/`__set_name__`, metaclasses). These are exactly the places where a "port from Java" would look different — and the module docstrings frequently call out the Python-specific simplification (e.g. "in Python the interface is simply a callable").

### 7.1 Error/exception inventory

The patterns raise a small, well-defined set of exceptions — useful when writing or reviewing tests:

| Exception | Message | Location |
|---|---|---|
| `NotImplementedError` | `Must provide implementation in subclass.` | `other/blackboard.py` (abstract expert) |
| `NotImplementedError` | `You should implement this!` | `structural/composite.py` (`Graphic.render`) |
| `KeyError` | `No controller registered for path '{path}'` | `structural/mvc.py` (`Router.resolve`) |
| `KeyError` | `... not in the model's item list.` | `structural/mvc.py` (`ProductModel.get`) |
| `ValueError` | `Invalid Value for Param: {param}` | `behavioral/catalog.py` (all four catalog classes) |
| `ValueError` | `Unsupported shape type` | `behavioral/servant.py` (`GeometryTools`) |
| `ValueError` | `Discount cannot be applied due to negative price resulting. {name}` | `behavioral/strategy.py` (`DiscountStrategyValidator`) |
| `UnsupportedMessageType` / `UnsupportedState` / `UnsupportedTransition` | (no message) | `other/hsm/hsm.py` |

---

## 8. Code Conventions

The contribution guidelines in the README codify the house style:

1. **Module docstring required.** Every pattern starts with a docstring describing the pattern, ideally with `*What is this pattern about?`, `*What does this example do?`, `*Where is the pattern used practically?`, `*References:`, and a `*TL;DR` line. `structural/facade.py` is cited as the gold-standard detailed example; `behavioral/template.py` as an acceptable shorter one.
2. **"Examples in Python ecosystem" sections** are encouraged where real-world equivalents exist (e.g. Django Signals for Observer, `ast.NodeVisitor` for Visitor, Django middleware for Chain of Responsibility).
3. **Type hints throughout.** Most files annotate parameters and return types; `mypy` runs in CI.
4. **Black formatting + isort ordering** are mandatory before submitting.
5. **Doctests as examples.** New patterns put their worked example in a `main()` docstring as a doctest so it is verified automatically.
6. **README update.** When a pattern is added or changed, the corresponding README table/section must be updated to match.

> [!IMPORTANT]
> The README explicitly states the project's editorial stance: emphasize *why* you'd choose a pattern (and its trade-offs) over *how* to implement it. Contributions that add an exotic implementation without explaining when to reach for it run against the grain of the project.

---

## 9. Contribution Workflow

```text
1. Implement / modify a pattern under patterns/<category>/<name>.py
2. Add a module docstring (why + example + references + TL;DR)
3. Add a main() doctest demonstrating usage
4. Add/adjust the mirror test under tests/<category>/test_<name>.py
5. Run quality gates:
     black .
     ./lint.sh         (bash-compatible shells)
     tox   or   tox -e ci37
6. Update the matching README section/table
7. Open a PR
```

Pre-submission checklist (from the README's "Travis CI" contribution note):

- [ ] `black .` applied
- [ ] `tox` (or `tox -e ci37`) passes
- [ ] `./lint.sh` clean (if you have a bash-compatible shell)
- [ ] README updated to reflect the change

> [!NOTE]
> The README also points contributors at **CodeTriage** for issue/PR triage, and notes that **Python 2-compatible** versions of some patterns are preserved on the `legacy` git tag — relevant if a contributor asks where Python 2 support went.

---

## 10. Security Analysis

There is no running service, no network surface, no authentication, no secrets, and no third-party runtime dependencies — so the conventional application threat model does not apply. The realistic security considerations are **repository-and-supply-chain** concerns:

| Concern | Assessment |
|---|---|
| Runtime dependency CVEs | **None** — standard-library only, so there is no third-party runtime attack surface |
| Dev-toolchain supply chain | The `dev` extra pulls black/flake8/mypy/tox/etc. from PyPI; pin versions (already done in `pyproject.toml`) and enable 2FA on the project's PyPI/GitHub accounts |
| CI token exposure | Travis + Codecov integration — keep the Codecov upload token and any Travis secrets out of the repo; they are not in the source tree |
| Untrusted example input | Patterns like `mvc.py` read `sys.argv` and `graph_search.py`/`hsm.py` process caller-supplied data, but they are illustrative; they perform no file/network/`eval` operations and are safe to run locally |
| Code-injection vectors | No use of `eval`, `exec`, `pickle.loads` on untrusted data, `subprocess`, or `os.system` in the pattern files |

> [!CAUTION]
> The biggest *governance* gap is the **missing LICENSE file** (tracked as issue #143). Without an explicit license, the default is "all rights reserved," which complicates downstream reuse despite the educational intent. This is a legal/compliance issue rather than a runtime security one, but it is the most consequential open item for anyone copying code out of the repo.

---

## 11. Known Issues & Improvement Opportunities

These are drawn from the project's own open GitHub issues (community-reported, real signal):

| # | Title | Type | Maintainer note |
|---|---|---|---|
| #143 | Needs a COPYRIGHT/LICENSE file | Governance | Highest-impact: blocks clean downstream reuse |
| #468 | Visualizing pattern relationships with Mermaid diagrams | Enhancement | README already uses some mermaid graphs; this would extend them |
| #373 | Support for type hints | Enhancement | Largely already in place; tracks completing coverage |
| #433 | Remove deprecated Python versions | Maintenance | Aligns with `requires-python >= 3.10` |
| #333 | Notebook version of the repo | Enhancement | Alternative presentation of the catalog |
| #277 | Code coverage (infrastructure) | Infrastructure | Coverage is configured via `pytest-cov` + Codecov; this tracks surfacing/raising it |
| #278 | Add DAO / DTO patterns | New content | Would extend the catalog |
| #245 | Add an automation-testing pattern | New content | Fits the design-for-testability bucket |
| #279 | List anti-patterns in README | Docs | Partially done — the README already has an Anti-Patterns section |
| #120 | `3-tier.py` and `mvc.py` are almost identical | Refactor/dedup | Both model a product catalog; worth differentiating or cross-referencing |
| #244 | Functional programming patterns (question) | Discussion | Scope question for the catalog |
| #437 | Replace setuptools with `pyproject.toml` | Build | **Closed** — the project now uses `pyproject.toml` with the setuptools build backend |

> [!TIP]
> Issue #120 (3-tier vs. MVC near-duplication) is a genuine code-quality observation: both files use the same milk/eggs/cheese product model and a similar layered structure. If you touch either, consider adding a comment cross-referencing the other and clarifying the *strict vs. non-strict* layering distinction that motivates having both.

### 11.1 Additional maintainer-visible gaps

- **README vs. file tree drift.** The README's behavioral table lists an `interpreter` pattern, but no `interpreter.py` exists in this revision. Either add the implementation or correct the table. (Per the README's own contribution rule #6, the table should track the files.)
- **Dev dependency duplication.** `requirements-dev.txt` (unpinned) and `pyproject.toml`'s `dev` extra (pinned) list overlapping but not identical tool sets. Consolidating to a single source would prevent drift.
- **Two flake8 line lengths** (120 in `pyproject.toml`, 88 in the `Makefile`) — reconcile to one.
- **Mostly-commented `tox` matrix.** The active `legacy_tox_ini` declares environments but leaves the command detail commented out; the real test commands effectively come from `pyproject.toml`'s `addopts`. Consider making `tox` self-contained again.

---

## 12. Quick Reference

### Commands

| Task | Command |
|---|---|
| Clone | `git clone https://github.com/faif/python-patterns.git` |
| Dev install | `python -m pip install -e ".[dev]"` |
| Run one pattern (verify) | `python patterns/<cat>/<name>.py` |
| Run one pattern (verbose) | `python -m doctest -v patterns/<cat>/<name>.py` |
| Run all doctests | `pytest --doctest-modules patterns/` |
| Full test + coverage | `pytest` |
| Quick unit tests | `pytest -c pytest_local.ini` |
| Format | `black .` |
| Full lint sequence | `./lint.sh` |
| Lint via Makefile | `make pylinter` (requires `./venv`) |
| CI environment | `tox` |
| Python 2 versions | `git checkout legacy` |

### Key files

| File | Purpose |
|---|---|
| `pyproject.toml` | Single source of truth: build, deps, pytest, coverage, mypy, flake8, tox |
| `pytest_local.ini` | Lightweight local pytest config (`-q`, tests only) |
| `lint.sh` | Canonical lint + test sequence |
| `Makefile` | `pylinter` / `pyupgrade` targets (assume `./venv`) |
| `.travis.yml` | CI: Python 3.12, `tox`, Codecov |
| `requirements-dev.txt` | Unpinned dev tool list (prefer `pyproject.toml` `dev` extra) |
| `.codespellignore` | Spelling-checker allowlist |
| `README.md` | Catalog tables, mermaid diagrams, anti-patterns, contribution rules |

### Configuration facts

| Setting | Value | Source |
|---|---|---|
| Minimum Python | 3.10 | `pyproject.toml` |
| CI Python | 3.12 | `.travis.yml` |
| Runtime dependencies | none | `pyproject.toml` |
| Random test seed | 1234 | `pyproject.toml` `addopts` |
| Coverage target package | `patterns` | `pyproject.toml` |
| flake8 line length | 120 (pyproject) / 88 (Makefile) | both |
| mypy Python version | 3.12, `ignore_missing_imports` | `pyproject.toml` |
| Build backend | `setuptools.build_meta` | `pyproject.toml` |
| Packaged package | `patterns` | `pyproject.toml` `[tool.setuptools]` |

---

_Generated June 2026 from faif/python-patterns at 74151cf. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
