summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2014-12-16 19:48:53 -0500
committerChris McDonough <chrism@plope.com>2014-12-16 19:48:53 -0500
commit27db38880d46b6f4345cf86766924de976e24177 (patch)
tree8c5dcf10f1177e6b0fc212cd8fa0eea20ecf9f5d
parentb1fac53cd0c3b930aec90e27f4d19c5f785f52e2 (diff)
parentcc15bbf7de74f4cdfc676e34fa429d2658d1ddf6 (diff)
downloadpyramid-27db38880d46b6f4345cf86766924de976e24177.tar.gz
pyramid-27db38880d46b6f4345cf86766924de976e24177.tar.bz2
pyramid-27db38880d46b6f4345cf86766924de976e24177.zip
Merge branch 'master' of github.com:Pylons/pyramid
-rw-r--r--.travis.yml23
-rw-r--r--CHANGES.txt47
-rw-r--r--CONTRIBUTORS.txt4
-rw-r--r--HACKING.txt2
-rw-r--r--README.rst7
-rw-r--r--RELEASING.txt3
-rw-r--r--TODO.txt5
-rw-r--r--docs/_static/pyramid_request_processing.graffle9748
-rw-r--r--docs/_static/pyramid_request_processing.pngbin0 -> 122854 bytes
-rw-r--r--docs/_static/pyramid_request_processing.svg3
-rw-r--r--docs/api/registry.rst12
-rw-r--r--docs/api/request.rst41
-rw-r--r--docs/api/security.rst2
-rw-r--r--docs/glossary.rst23
-rw-r--r--docs/narr/MyProject/myproject/tests.py37
-rw-r--r--docs/narr/MyProject/setup.py45
-rw-r--r--docs/narr/assets.rst68
-rw-r--r--docs/narr/router.rst3
-rw-r--r--docs/narr/security.rst94
-rw-r--r--docs/narr/testing.rst142
-rw-r--r--docs/tutorials/wiki/design.rst4
-rw-r--r--docs/tutorials/wiki2/design.rst3
-rw-r--r--pyramid/authentication.py29
-rw-r--r--pyramid/config/assets.py216
-rw-r--r--pyramid/config/views.py6
-rw-r--r--pyramid/interfaces.py57
-rw-r--r--pyramid/registry.py5
-rw-r--r--pyramid/scripts/proutes.py68
-rw-r--r--pyramid/scripts/pshell.py9
-rw-r--r--pyramid/security.py25
-rw-r--r--pyramid/testing.py4
-rw-r--r--pyramid/tests/test_authentication.py16
-rw-r--r--pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt0
-rw-r--r--pyramid/tests/test_config/test_assets.py439
-rw-r--r--pyramid/tests/test_config/test_views.py7
-rw-r--r--pyramid/tests/test_integration.py2
-rw-r--r--pyramid/tests/test_registry.py5
-rw-r--r--pyramid/tests/test_scripts/pystartup.py1
-rw-r--r--pyramid/tests/test_scripts/test_proutes.py93
-rw-r--r--pyramid/tests/test_scripts/test_pshell.py23
-rw-r--r--pyramid/tests/test_security.py21
-rw-r--r--pyramid/tests/test_util.py43
-rw-r--r--pyramid/util.py32
-rw-r--r--setup.cfg1
-rw-r--r--tox.ini2
45 files changed, 10997 insertions, 423 deletions
diff --git a/.travis.yml b/.travis.yml
index 4ca998c42..5a205b268 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,21 @@
# Wire up travis
language: python
-python:
- - 2.6
- - 2.7
- - pypy
- - 3.2
- - 3.3
- - 3.4
- - pypy3
+env:
+ - TOXENV=py26
+ - TOXENV=py27
+ - TOXENV=py32
+ - TOXENV=py33
+ - TOXENV=py34
+ - TOXENV=pypy
+ - TOXENV=pypy3
+ - TOXENV=cover
-install: python setup.py dev
+install:
+ - travis_retry pip install tox
-script: python setup.py test -q
+script:
+ - travis_retry tox
notifications:
email:
diff --git a/CHANGES.txt b/CHANGES.txt
index b5d08c8ff..46c331268 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,9 @@ Next release
Features
--------
+- Added support / testing for 'pypy3' under Tox and Travis.
+ See https://github.com/Pylons/pyramid/pull/1469
+
- Cache busting for static resources has been added and is available via a new
argument to ``pyramid.config.Configurator.add_static_view``: ``cachebust``.
See https://github.com/Pylons/pyramid/pull/1380
@@ -12,8 +15,8 @@ Features
parameter to assist with includeable packages that wish to resolve
resources relative to the package in which the ``Configurator`` was created.
This is especially useful for addons that need to load asset specs from
- settings, in which case it is natural for a user to define things relative
- to their own packages.
+ settings, in which case it is may be natural for a developer to define
+ imports or assets relative to the top-level package.
See https://github.com/Pylons/pyramid/pull/1337
- Added line numbers to the log formatters in the scaffolds to assist with
@@ -24,12 +27,38 @@ Features
``431 Request Header Fields Too Large`` in ``pyramid.httpexceptions``.
See https://github.com/Pylons/pyramid/pull/1372/files
+- The ``pshell`` script will now load a ``PYTHONSTARTUP`` file if one is
+ defined in the environment prior to launching the interpreter.
+ See https://github.com/Pylons/pyramid/pull/1448
+
- Make it simple to define notfound and forbidden views that wish to use
the default exception-response view but with altered predicates and other
configuration options. The ``view`` argument is now optional in
``config.add_notfound_view`` and ``config.add_forbidden_view``..
See https://github.com/Pylons/pyramid/issues/494
+- Greatly improve the readability of the ``pcreate`` shell script output.
+ See https://github.com/Pylons/pyramid/pull/1453
+
+- Improve robustness to timing attacks in the ``AuthTktCookieHelper`` and
+ the ``SignedCookieSessionFactory`` classes by using the stdlib's
+ ``hmac.compare_digest`` if it is available (such as Python 2.7.7+ and 3.3+).
+ See https://github.com/Pylons/pyramid/pull/1457
+
+- Assets can now be overidden by an absolute path on the filesystem when using
+ the ``config.override_asset`` API. This makes it possible to fully support
+ serving up static content from a mutable directory while still being able
+ to use the ``request.static_url`` API and ``config.add_static_view``.
+ Previously it was not possible to use ``config.add_static_view`` with an
+ absolute path **and** generate urls to the content. This change replaces
+ the call, ``config.add_static_view('/abs/path', 'static')``, with
+ ``config.add_static_view('myapp:static', 'static')`` and
+ ``config.override_asset(to_override='myapp:static/',
+ override_with='/abs/path/')``. The ``myapp:static`` asset spec is completely
+ made up and does not need to exist - it is used for generating urls
+ via ``request.static_url('myapp:static/foo.png')``.
+ See https://github.com/Pylons/pyramid/issues/1252
+
Bug Fixes
---------
@@ -67,6 +96,16 @@ Bug Fixes
- Fix a failing unittest caused by differing mimetypes across various OSs.
See https://github.com/Pylons/pyramid/issues/1405
+- Fix route generation for static view asset specifications having no path.
+ See https://github.com/Pylons/pyramid/pull/1377
+
+Deprecations
+------------
+
+- Renamed the ``principal`` argument to ``pyramid.security.remember()`` to
+ ``userid`` in order to clarify its intended purpose.
+ See https://github.com/Pylons/pyramid/pull/1399
+
Docs
----
@@ -77,6 +116,10 @@ Docs
- Clarify a previously-implied detail of the ``ISession.invalidate`` API
documentation.
+- Improve and clarify the documentation on what Pyramid defines as a
+ ``principal`` and a ``userid`` in its security APIs.
+ See https://github.com/Pylons/pyramid/pull/1399
+
Scaffolds
---------
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index c77d3e92c..9c2191f3b 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -232,3 +232,7 @@ Contributors
- Amit Mane, 2014/01/23
- Fenton Travers, 2014/05/06
+
+- Randall Leeds, 2014/11/11
+
+- Hugo Branquinho, 2014/11/25
diff --git a/HACKING.txt b/HACKING.txt
index e3afbf241..16c17699c 100644
--- a/HACKING.txt
+++ b/HACKING.txt
@@ -31,7 +31,7 @@ By Hand
$ cd hack-on-pyramid
# Configure remotes such that you can pull changes from the Pyramid
# repository into your local repository.
- $ git remote add upstream https://github.com:Pylons/pyramid.git
+ $ git remote add upstream https://github.com/Pylons/pyramid.git
# fetch and merge changes from upstream into master
$ git fetch upstream
$ git merge upstream/master
diff --git a/README.rst b/README.rst
index a3458028b..adf7eea5e 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,13 @@
Pyramid
=======
+.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=master
+ :target: https://travis-ci.org/Pylons/pyramid
+
+.. image:: https://readthedocs.org/projects/pyramid/badge/?version=master
+ :target: http://docs.pylonsproject.org/projects/pyramid/en/master/
+ :alt: Documentation Status
+
Pyramid is a small, fast, down-to-earth, open source Python web framework.
It makes real-world web application development and
deployment more fun, more predictable, and more productive.
diff --git a/RELEASING.txt b/RELEASING.txt
index 553d2dcf2..0adef552c 100644
--- a/RELEASING.txt
+++ b/RELEASING.txt
@@ -26,6 +26,9 @@ Releasing Pyramid
- Copy relevant changes (delta bug fixes) from CHANGES.txt to
docs/whatsnew-X.X (if it's a major release).
+- update README.rst to use correct versions of badges and URLs according to
+ each branch and context, i.e., RTD "latest" == GitHub/Travis "1.x-branch".
+
- Make sure docs render OK::
$ cd docs
diff --git a/TODO.txt b/TODO.txt
index 62b8c39f4..e738b58d8 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -125,7 +125,10 @@ Future
- 1.7: Change ``pyramid.authentication.AuthTktAuthenticationPolicy`` default
``hashalg`` to ``sha512``.
-- 1.8 Remove set_request_property.
+- 1.8: Remove set_request_property.
+
+- 1.9: Remove extra code enabling ``pyramid.security.remember(principal=...)``
+ and force use of ``userid``.
Probably Bad Ideas
------------------
diff --git a/docs/_static/pyramid_request_processing.graffle b/docs/_static/pyramid_request_processing.graffle
new file mode 100644
index 000000000..71319610b
--- /dev/null
+++ b/docs/_static/pyramid_request_processing.graffle
@@ -0,0 +1,9748 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>ApplicationVersion</key>
+ <array>
+ <string>com.omnigroup.OmniGrafflePro</string>
+ <string>139.18.0.187838</string>
+ </array>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>BackgroundGraphic</key>
+ <dict>
+ <key>Bounds</key>
+ <string>{{0, 0}, {576, 733}}</string>
+ <key>Class</key>
+ <string>SolidGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>ID</key>
+ <integer>2</integer>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ </dict>
+ <key>BaseZoom</key>
+ <integer>0</integer>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>CreationDate</key>
+ <string>2014-11-18 08:33:33 +0000</string>
+ <key>Creator</key>
+ <string>Steve Piercy</string>
+ <key>DisplayScale</key>
+ <string>1 0/72 in = 1 0/72 in</string>
+ <key>GraphDocumentVersion</key>
+ <integer>8</integer>
+ <key>GraphicsList</key>
+ <array>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169389</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169504</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.41667175292969, 402.88506673894034}</string>
+ <string>{375.5, 402.27232108797347}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169428</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169382</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169433</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 459.27667544230695}</string>
+ <string>{238.5002713470962, 456.52468399152298}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169370</integer>
+ <key>Position</key>
+ <real>0.28820157051086426</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169383</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169432</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 482.12574895537085}</string>
+ <string>{238.52297468463752, 508.35839132916635}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169370</integer>
+ <key>Position</key>
+ <real>0.5668826699256897</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.8333613077798, 284.99999999999994}, {105.66668701171875, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169425</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 authorization}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 412.15071036499205}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169426</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, 0.5}</string>
+ <string>{-0.49999999999999911, 0.49999999999999289}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 303.65604172230951}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169427</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 393.55704269887212}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169428</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response adapter}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 374.90099016834085}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169429</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 341.36561209044055}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169430</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.75000762939453, 322.26348241170439}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169431</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169424</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169422</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169423</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 470.25295298442387}</string>
+ <string>{238.33861159880226, 482.4262543949045}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169370</integer>
+ <key>Position</key>
+ <real>0.42701038718223572</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 471.22620192028251}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169422</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewResponse}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169420</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169421</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{154.99998733539806, 128.68025330008533}</string>
+ <string>{239.83340199788393, 128.59152244387357}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169386</integer>
+ <key>Position</key>
+ <real>0.35945424437522888</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239.83340199788395, 117.31920169649808}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169420</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewRequest}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.1666056315114, 148.28868579864499}, {105.66669464111328, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169418</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 URL dispatch}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.1666056315114, 181.37798023223874}, {105.66669464111328, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169419</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 route predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169418</integer>
+ <integer>169419</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169417</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16666158040482, 272}, {105.66666412353516, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169412</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view lookup}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16666158040482, 305.08929443359375}, {105.66666412353516, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169413</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169412</integer>
+ <integer>169413</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169411</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169407</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169410</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{238.75000762939462, 430.80675844512831}</string>
+ <string>{207.66666666666765, 385.656005859375}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169426</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169407</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169409</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{239.33336141608385, 285.57837549845181}</string>
+ <string>{207.66666666666777, 353.07514659563753}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169425</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169381</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169408</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 386.66442959065108}</string>
+ <string>{155.00000254313238, 422.21209462483216}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169407</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 353.07514659563753}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169407</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.49211360058019871, -0.49251945318722434}</string>
+ <string>{-0.49211360058019871, 0.49470854679786669}</string>
+ <string>{0.4984227008620481, 0.48463479169597612}</string>
+ <string>{0.49842270086204898, -0.5}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view pipeline}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169380</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169399</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{154.9999936421724, 258.44082431579938}</string>
+ <string>{238.8333613077798, 258.45536063967575}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169372</integer>
+ <key>Position</key>
+ <real>0.51973581314086914</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383.66662216186666, 130.51770718892479}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169393</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 internal process}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383.66662216186666, 91.940789540609359}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169394</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 external process (middleware, tween)}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383.66662216186666, 158.54998334248924}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169395</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383.66662216186666, 186.58225949605369}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169396</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 callback}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383.66662216186666, 63.908513387045019}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169397</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 event}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{370.9999504089372, 42.910746256511771}, {132.66667175292969, 184.08924865722656}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169398</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 0.5}</string>
+ <string>{1, -0.5}</string>
+ <string>{-1, 0.5}</string>
+ <string>{-1, -0.5}</string>
+ <string>{0.5, 1}</string>
+ <string>{-0.5, 1}</string>
+ <string>{0.5, -1}</string>
+ <string>{-0.5, -1}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Align</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
+
+\f0\b\fs20 \cf0 Legend}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>TextPlacement</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169391</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{233.5000012715667, 20.000000000000934}, {116, 14}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>ID</key>
+ <integer>169390</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf0 &lt;%Canvas%&gt;}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{375.5, 391}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169389</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 BeforeRender}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169418</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169386</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000170434049, 119.22767858295661}</string>
+ <string>{154.99995295206804, 148.28868579864499}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169378</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169378</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169385</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 67.727678571434836}</string>
+ <string>{155.00000254313238, 96.18303707668386}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169377</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 509.6179466247504}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169384</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 497.23589324949899}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169383</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 finished callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 445.23589324949717}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169382</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 422.21209462483216}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169381</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 247.18303989230026}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169380</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 ContextFound}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 222.18303707668389}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169379</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 traversal}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 96.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169378</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102.16667048136482, 45.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169377</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware ingress }</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169379</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169373</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{154.99995295206804, 198.62202930450437}</string>
+ <string>{155.00000254313238, 222.18303707668389}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169419</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169412</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169372</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{154.9999936421724, 245.22767856643924}</string>
+ <string>{154.9999936421724, 272}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169379</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169407</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169371</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{154.9999936421724, 322.33334350585938}</string>
+ <string>{155.00000254313238, 353.07514659563753}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169413</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9839935302734375}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169384</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169370</integer>
+ <key>Layer</key>
+ <integer>0</integer>
+ <key>Points</key>
+ <array>
+ <string>{155.00000254313238, 444.75673611958314}</string>
+ <string>{155.00000254313238, 509.6179466247504}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169381</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169444</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169503</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.4166717529298, 537.32234122436705}</string>
+ <string>{420.4999504089364, 515.08928491955714}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169494</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169444</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169502</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.50004831949906, 391.51558277923863}</string>
+ <string>{420.4999504089364, 472.78869058972316}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169493</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169450</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169501</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 592.81693102013151}</string>
+ <string>{239, 583.78422005970799}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169438</integer>
+ <key>Position</key>
+ <real>0.28820157051086426</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169451</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169500</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 629.80996162681686}</string>
+ <string>{239, 640.78422005970981}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169438</integer>
+ <key>Position</key>
+ <real>0.5668826699256897</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.8333613077798, 391.51558277923863}, {105.66668701171875, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169493</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 authorization}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 518.66629314423074}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169494</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, 0.5}</string>
+ <string>{-0.49999999999999911, 0.49999999999999289}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 410.17162450154819}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169495</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 500.07262547811081}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169496</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response adapter}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 481.41657294757954}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169497</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 447.88119486967923}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169498</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 428.77906519094307}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169499</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169492</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169490</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169491</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.166643778483959, 611.77452873049333}</string>
+ <string>{238.8333613077798, 611.77452873049333}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 600.50220798311784}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169490</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewResponse}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169488</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169489</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999986314263907, 140.3328574622312}</string>
+ <string>{239.83340199788393, 141.59152244387357}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169454</integer>
+ <key>Position</key>
+ <real>0.35945424437522888</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239.83340199788395, 130.31920169649808}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169488</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewRequest}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166605631511416, 166.28868579864499}, {105.66668701171875, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169486</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 URL dispatch}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166605631511416, 199.37798023223874}, {105.66668701171875, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169487</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 route predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169486</integer>
+ <integer>169487</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169485</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.5000406901047, 338.15028762817326}, {105.66668701171875, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169483</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view lookup}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.5000406901047, 371.23958206176701}, {105.66668701171875, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169484</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169483</integer>
+ <integer>169484</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169482</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166661580404835, 335}, {105.66667175292969, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169480</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view lookup}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166661580404835, 368.08929443359375}, {105.66667175292969, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169481</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169480</integer>
+ <integer>169481</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169479</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169475</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169478</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{166.75000762939462, 537.32234122436694}</string>
+ <string>{135.66666666666765, 485}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169494</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169475</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169477</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{167.33336141608385, 392.09395827769049}</string>
+ <string>{135.66666666666777, 452.41914073626253}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169493</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169449</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169476</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 485.50842372576449}</string>
+ <string>{83.000002543132396, 548.10604731241608}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169475</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 452.41914073626253}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169475</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.49211360058019871, -0.49251945318722434}</string>
+ <string>{-0.49211360058019871, 0.49470854679786669}</string>
+ <string>{0.4984227008620481, 0.48463479169597612}</string>
+ <string>{0.49842270086204898, -0.5}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view pipeline}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{51.333333333333314, 0}</string>
+ <string>{-0.66666666666662877, 58.666666666666686}</string>
+ <string>{0.66673293066804717, -58.666850540458825}</string>
+ <string>{-16.306719354194399, 0.26652623861849634}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169443</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169474</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{369.66666666666669, 541}</string>
+ <string>{404.00000000000023, 362}</string>
+ <string>{420.36749776329049, 302.42112495959606}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.75663</string>
+ <key>g</key>
+ <string>0.756618</string>
+ <key>r</key>
+ <string>0.75664</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{69.833333333332462, -0.72767857143483639}</string>
+ <string>{-0.66690523835279691, -51.044605218028948}</string>
+ <string>{0.66666666666674246, 51.044637362162291}</string>
+ <string>{-24.333271383961971, -0.13425428344572765}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169443</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169473</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{310.66666666666754, 118.72767857143484}</string>
+ <string>{399.33333333333417, 216.62202930450439}</string>
+ <string>{420.37955338188368, 301.45369961823752}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.75663</string>
+ <key>g</key>
+ <string>0.756618</string>
+ <key>r</key>
+ <string>0.75664</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{-3.9999491373696401, 78.910715080442856}</string>
+ <string>{92.666683130060392, 0.22547126950667007}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169490</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169472</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33328247070392, 515.08928491955714}</string>
+ <string>{344.50002543131501, 611.77452873049333}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169444</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-32.166667938232536, 10.244050343831077}</string>
+ </array>
+ <key>ID</key>
+ <integer>169471</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.96346869509995, 346.26317428240412}</string>
+ <string>{389.8333346048999, 328.08928298950207}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169456</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-28.500001271565793, 8.3333333333333144}</string>
+ </array>
+ <key>ID</key>
+ <integer>169470</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.98861594084059, 323.71068461220347}</string>
+ <string>{391.1666679382335, 313.6666666666664}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169455</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-40, 1.5446373167492311}</string>
+ </array>
+ <key>ID</key>
+ <integer>169469</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.9995533451783, 301.1612218744512}</string>
+ <string>{394.50000127156665, 299.00000000000045}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169442</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{8.5833282470703125, -10.244596987647753}</string>
+ <string>{0, 0}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169457</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169468</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.41667175292969, 509.40064951817902}</string>
+ <string>{285.5, 503.81699882234847}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169496</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169448</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169467</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 300.27229985501288}</string>
+ <string>{238.34892458824362, 260.57913893040109}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169440</integer>
+ <key>Position</key>
+ <real>0.51973581314086914</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 214.61452811107179}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169460</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.756045</string>
+ <key>g</key>
+ <string>0.75004</string>
+ <key>r</key>
+ <string>0.994455</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 exception}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 130.51770718892479}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169461</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 internal process}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 91.940789540609359}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169462</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 external process (middleware, tween)}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 158.54998334248924}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169463</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 186.58225949605369}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169464</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 callback}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 63.908513387045019}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169465</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 event}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{406.9999504089372, 42.910746256511771}, {132.66667175292969, 207.81692504882812}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169466</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 0.5}</string>
+ <string>{1, -0.5}</string>
+ <string>{-1, 0.5}</string>
+ <string>{-1, -0.5}</string>
+ <string>{0.5, 1}</string>
+ <string>{-0.5, 1}</string>
+ <string>{0.5, -1}</string>
+ <string>{-0.5, -1}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Align</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
+
+\f0\b\fs20 \cf0 Legend}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>TextPlacement</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169459</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{233.5000012715667, 20.000000000000934}, {116, 14}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>ID</key>
+ <integer>169458</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf0 &lt;%Canvas%&gt;}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{285.5, 492.544677734375}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169457</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 BeforeRender}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83337529500417, 335.17855853126167}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169456</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 HTTPForbidden}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83337529500417, 312.54463200342093}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169455</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 PredicateMismatch}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169486</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169454</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000001850648417, 128.2276785555359}</string>
+ <string>{82.999949137370791, 166.28868579864502}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169446</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169446</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169453</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 67.727678571434836}</string>
+ <string>{83.000002543132396, 105.18303707668386}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169445</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 671.51189931233432}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169452</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 629.51189931233432}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169451</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 finished callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 572.5118993123325}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169450</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 548.10604731241608}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169449</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 249.18303989230026}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169448</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 ContextFound}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 240.18303707668389}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169447</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 traversal}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 105.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169446</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 45.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169445</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware ingress }</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.49995040893634, 472.78869058972316}, {105.66666412353516, 42.300594329833984}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169444</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.49999999999999956, -0.5}</string>
+ <string>{-0.49999999999999956, 0.5}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 notfound_view / forbidden_view / exception_view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.49995040893634, 290.66666666666691}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169443</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.756045</string>
+ <key>g</key>
+ <string>0.75004</string>
+ <key>r</key>
+ <string>0.994455</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 exception}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336512247806, 289.91071033477789}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169442</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 HTTPNotFound}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169447</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169441</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999949137370791, 216.62202930450437}</string>
+ <string>{83.000002543132396, 240.18303707668389}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169487</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169480</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169440</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 263.22767855635425}</string>
+ <string>{82.999997456869679, 335}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169447</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169475</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169439</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 385.33334350585938}</string>
+ <string>{83.000002543132396, 452.41914073626253}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169481</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9839935302734375}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169452</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169438</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 571.15068879140836}</string>
+ <string>{83.000002543132396, 671.51189931233421}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169449</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.055999755859375}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169483</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169437</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33328247070392, 313.2113088426139}</string>
+ <string>{473.33338419596407, 338.15028762817326}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169443</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840011596679688}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169444</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169436</integer>
+ <key>Layer</key>
+ <integer>1</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33338359264764, 388.98363112285512}</string>
+ <string>{473.33328247070392, 472.78869058972316}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169484</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169358</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169359</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.4166717529298, 537.32234122436705}</string>
+ <string>{420.4999504089364, 515.08928491955714}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169206</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169358</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169360</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.50004831949906, 391.51558277923863}</string>
+ <string>{420.4999504089364, 472.78869058972316}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169205</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169044</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169130</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 592.81693102013151}</string>
+ <string>{239, 583.78422005970799}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169128</integer>
+ <key>Position</key>
+ <real>0.28820157051086426</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169045</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169129</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 629.80996162681686}</string>
+ <string>{239, 640.78422005970981}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169128</integer>
+ <key>Position</key>
+ <real>0.5668826699256897</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.8333613077798, 391.51558277923863}, {105.66668701171875, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169205</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 authorization}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 518.66629314423074}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169206</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, 0.5}</string>
+ <string>{-0.49999999999999911, 0.49999999999999289}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 410.17162450154819}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169207</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{0.50000000000000089, -0.49999999999999645}</string>
+ <string>{-0.49526813868737474, -0.4689979626999552}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 decorators ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 500.07262547811081}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169208</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response adapter}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 481.41657294757954}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169209</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 447.88119486967923}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169210</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{166.75000762939453, 428.77906519094307}, {105.66666412353516, 18.656048080136394}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169211</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.637876</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view mapper ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169204</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169085</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169086</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.166643778483959, 611.77452873049333}</string>
+ <string>{238.8333613077798, 611.77452873049333}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 600.50220798311784}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169085</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewResponse}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169083</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169084</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999986314263907, 140.3328574622312}</string>
+ <string>{239.83340199788393, 141.59152244387357}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169048</integer>
+ <key>Position</key>
+ <real>0.35945424437522888</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239.83340199788395, 130.31920169649808}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169083</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 NewRequest}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166605631511416, 166.28868579864499}, {105.66668701171875, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169081</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 URL dispatch}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166605631511416, 199.37798023223874}, {105.66668701171875, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169082</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 route predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169081</integer>
+ <integer>169082</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169080</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.5000406901047, 338.15028762817326}, {105.66668701171875, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169355</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view lookup}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.5000406901047, 371.23958206176701}, {105.66668701171875, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169356</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169355</integer>
+ <integer>169356</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169354</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>TableGroup</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166661580404835, 335}, {105.66667175292969, 33.08929443359375}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169075</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view lookup}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166661580404835, 368.08929443359375}, {105.66667175292969, 17.244049072265625}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169076</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 predicates}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridH</key>
+ <array>
+ <integer>169075</integer>
+ <integer>169076</integer>
+ <array/>
+ </array>
+ <key>ID</key>
+ <integer>169074</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169070</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169073</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{166.75000762939462, 537.32234122436694}</string>
+ <string>{135.66666666666765, 485}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169206</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169070</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169072</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{167.33336141608385, 392.09395827769049}</string>
+ <string>{135.66666666666777, 452.41914073626253}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.755269</string>
+ <key>g</key>
+ <string>0.755239</string>
+ <key>r</key>
+ <string>0.75529</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>11</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169205</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169043</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169071</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 485.50842372576449}</string>
+ <string>{83.000002543132396, 548.10604731241608}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169070</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 452.41914073626253}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169070</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.49211360058019871, -0.49251945318722434}</string>
+ <string>{-0.49211360058019871, 0.49470854679786669}</string>
+ <string>{0.4984227008620481, 0.48463479169597612}</string>
+ <string>{0.49842270086204898, -0.5}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view pipeline}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{51.333333333333314, 0}</string>
+ <string>{-0.66666666666662877, 58.666666666666686}</string>
+ <string>{0.66673293066804717, -58.666850540458825}</string>
+ <string>{-16.306719354194399, 0.26652623861849634}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169344</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169345</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{369.66666666666669, 541}</string>
+ <string>{404.00000000000023, 362}</string>
+ <string>{420.36749776329049, 302.42112495959606}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.75663</string>
+ <key>g</key>
+ <string>0.756618</string>
+ <key>r</key>
+ <string>0.75664</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{69.833333333332462, -0.72767857143483639}</string>
+ <string>{-0.66690523835279691, -51.044605218028948}</string>
+ <string>{0.66666666666674246, 51.044637362162291}</string>
+ <string>{-24.333271383961971, -0.13425428344572765}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169344</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169346</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{310.66666666666754, 118.72767857143484}</string>
+ <string>{399.33333333333417, 216.62202930450439}</string>
+ <string>{420.37955338188368, 301.45369961823752}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.75663</string>
+ <key>g</key>
+ <string>0.756618</string>
+ <key>r</key>
+ <string>0.75664</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{-3.9999491373696401, 78.910715080442856}</string>
+ <string>{92.666683130060392, 0.22547126950667007}</string>
+ </array>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169085</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169361</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33328247070392, 515.08928491955714}</string>
+ <string>{344.50002543131501, 611.77452873049333}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169358</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-32.166667938232536, 10.244050343831077}</string>
+ </array>
+ <key>ID</key>
+ <integer>169341</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.96346869509995, 346.26317428240412}</string>
+ <string>{389.8333346048999, 328.08928298950207}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169340</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-28.500001271565793, 8.3333333333333144}</string>
+ </array>
+ <key>ID</key>
+ <integer>169337</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.98861594084059, 323.71068461220347}</string>
+ <string>{391.1666679382335, 313.6666666666664}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169336</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{31.999987284342428, -14.081351280212308}</string>
+ <string>{-40, 1.5446373167492311}</string>
+ </array>
+ <key>ID</key>
+ <integer>169333</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{344.9995533451783, 301.1612218744512}</string>
+ <string>{394.50000127156665, 299.00000000000045}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169332</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{8.5833282470703125, -10.244596987647753}</string>
+ <string>{0, 0}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169051</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169062</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{272.41667175292969, 509.40064951817902}</string>
+ <string>{285.5, 503.81699882234847}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>Pattern</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169208</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169042</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169061</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 300.27229985501288}</string>
+ <string>{238.34892458824362, 260.57913893040109}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>Pattern</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169034</integer>
+ <key>Position</key>
+ <real>0.51973581314086914</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 214.61452811107179}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169054</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.756045</string>
+ <key>g</key>
+ <string>0.75004</string>
+ <key>r</key>
+ <string>0.994455</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 exception}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 130.51770718892479}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169055</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 internal process}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 91.940789540609359}, {105.66666412353516, 33.089282989501953}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169056</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 external process (middleware, tween)}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 158.54998334248924}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169057</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 186.58225949605369}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169058</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 callback}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{419.66662216186666, 63.908513387045019}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169059</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 event}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{406.9999504089372, 42.910746256511771}, {132.66667175292969, 207.81692504882812}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169060</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 0.5}</string>
+ <string>{1, -0.5}</string>
+ <string>{-1, 0.5}</string>
+ <string>{-1, -0.5}</string>
+ <string>{0.5, 1}</string>
+ <string>{-0.5, 1}</string>
+ <string>{0.5, -1}</string>
+ <string>{-0.5, -1}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>CornerRadius</key>
+ <real>5</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Align</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
+
+\f0\b\fs20 \cf0 Legend}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>TextPlacement</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>169053</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{233.5000012715667, 20.000000000000934}, {116, 14}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>ID</key>
+ <integer>169052</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\b\fs24 \cf0 &lt;%Canvas%&gt;}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{285.5, 492.544677734375}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169051</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 BeforeRender}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83337529500417, 335.17855853126167}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169340</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 HTTPForbidden}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83337529500417, 312.54463200342093}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169336</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 PredicateMismatch}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169081</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169048</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000001850648417, 128.2276785555359}</string>
+ <string>{82.999949137370791, 166.28868579864502}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169040</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169040</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169047</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 67.727678571434836}</string>
+ <string>{83.000002543132396, 105.18303707668386}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169039</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 671.51189931233432}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169046</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 629.51189931233432}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169045</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 finished callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{239, 572.5118993123325}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169044</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.327428</string>
+ <key>g</key>
+ <string>0.81823</string>
+ <key>r</key>
+ <string>0.995566</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 response callbacks}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 548.10604731241608}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169043</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween egress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336130777977, 249.18303989230026}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169042</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999449</string>
+ <key>g</key>
+ <string>0.743511</string>
+ <key>r</key>
+ <string>0.872276</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 ContextFound}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 240.18303707668389}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169041</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.815377</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>0.820561</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 traversal}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 105.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169040</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 tween ingress}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{30.166670481364818, 45.18303707668386}, {105.66666412353516, 22.544641494750977}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169039</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.999208</string>
+ <key>g</key>
+ <string>0.811343</string>
+ <key>r</key>
+ <string>0.644457</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 middleware ingress }</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.49995040893634, 472.78869058972316}, {105.66666412353516, 42.300594329833984}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169358</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.49999999999999956, -0.5}</string>
+ <string>{-0.49999999999999956, 0.5}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.422927</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 notfound_view / forbidden_view / exception_view}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{420.49995040893634, 290.66666666666691}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169344</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.756045</string>
+ <key>g</key>
+ <string>0.75004</string>
+ <key>r</key>
+ <string>0.994455</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 exception}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238.83336512247806, 289.91071033477789}, {105.66666412353516, 22.544642175946908}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>169332</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>ShadowVector</key>
+ <string>{2, 2}</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 HTTPNotFound}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169041</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169035</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999949137370791, 216.62202930450437}</string>
+ <string>{83.000002543132396, 240.18303707668389}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169082</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.05596923828125}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169075</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169034</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 263.22767855635425}</string>
+ <string>{82.999997456869679, 335}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169041</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840087890625}</string>
+ <string>{0, -8.9999999999999432}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169070</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169033</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{82.999997456869679, 385.33334350585938}</string>
+ <string>{83.000002543132396, 452.41914073626253}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169076</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9839935302734375}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169046</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169128</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{83.000002543132396, 571.15068879140836}</string>
+ <string>{83.000002543132396, 671.51189931233421}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169043</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 7.055999755859375}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169355</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169357</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33328247070392, 313.2113088426139}</string>
+ <string>{473.33338419596407, 338.15028762817326}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169344</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ControlPoints</key>
+ <array>
+ <string>{0, 6.9840011596679688}</string>
+ <string>{0, -9}</string>
+ </array>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>169358</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169362</integer>
+ <key>Layer</key>
+ <integer>2</integer>
+ <key>Points</key>
+ <array>
+ <string>{473.33338359264764, 388.98363112285512}</string>
+ <string>{473.33328247070392, 472.78869058972316}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Bezier</key>
+ <true/>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.0980392</string>
+ <key>g</key>
+ <string>0.0980392</string>
+ <key>r</key>
+ <string>0.0980392</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>SharpArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>169356</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <dict/>
+ <key>GuidesLocked</key>
+ <string>NO</string>
+ <key>GuidesVisible</key>
+ <string>YES</string>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>ImageCounter</key>
+ <integer>3</integer>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>no exceptions</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>exceptions only</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>all</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>NO</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>Animate</key>
+ <string>NO</string>
+ <key>circoMinDist</key>
+ <real>18</real>
+ <key>circoSeparation</key>
+ <real>0.0</real>
+ <key>layoutEngine</key>
+ <string>dot</string>
+ <key>neatoSeparation</key>
+ <real>0.0</real>
+ <key>twopiSeparation</key>
+ <real>0.0</real>
+ </dict>
+ <key>LinksVisible</key>
+ <string>NO</string>
+ <key>MagnetsVisible</key>
+ <string>NO</string>
+ <key>MasterSheets</key>
+ <array/>
+ <key>ModificationDate</key>
+ <string>2014-11-23 07:19:11 +0000</string>
+ <key>Modifier</key>
+ <string>Steve Piercy</string>
+ <key>NotesVisible</key>
+ <string>NO</string>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OriginVisible</key>
+ <string>NO</string>
+ <key>PageBreaks</key>
+ <string>YES</string>
+ <key>PrintInfo</key>
+ <dict>
+ <key>NSBottomMargin</key>
+ <array>
+ <string>float</string>
+ <string>41</string>
+ </array>
+ <key>NSHorizonalPagination</key>
+ <array>
+ <string>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
+ </array>
+ <key>NSLeftMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSPaperSize</key>
+ <array>
+ <string>size</string>
+ <string>{612, 792}</string>
+ </array>
+ <key>NSPrintReverseOrientation</key>
+ <array>
+ <string>int</string>
+ <string>0</string>
+ </array>
+ <key>NSRightMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSTopMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ </dict>
+ <key>PrintOnePage</key>
+ <false/>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Request Processing</string>
+ <key>SmartAlignmentGuidesActive</key>
+ <string>YES</string>
+ <key>SmartDistanceGuidesActive</key>
+ <string>YES</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>UseEntirePage</key>
+ <false/>
+ <key>VPages</key>
+ <integer>1</integer>
+ <key>WindowInfo</key>
+ <dict>
+ <key>CurrentSheet</key>
+ <integer>0</integer>
+ <key>ExpandedCanvases</key>
+ <array>
+ <dict>
+ <key>name</key>
+ <string>Request Processing</string>
+ </dict>
+ </array>
+ <key>Frame</key>
+ <string>{{35, 93}, {1394, 1325}}</string>
+ <key>ListView</key>
+ <true/>
+ <key>OutlineWidth</key>
+ <integer>178</integer>
+ <key>RightSidebar</key>
+ <true/>
+ <key>ShowRuler</key>
+ <true/>
+ <key>Sidebar</key>
+ <true/>
+ <key>SidebarWidth</key>
+ <integer>163</integer>
+ <key>VisibleRegion</key>
+ <string>{{-231, -226}, {1037, 1186}}</string>
+ <key>Zoom</key>
+ <real>1</real>
+ <key>ZoomValues</key>
+ <array>
+ <array>
+ <string>Request Processing</string>
+ <real>1</real>
+ <real>2</real>
+ </array>
+ </array>
+ </dict>
+</dict>
+</plist>
diff --git a/docs/_static/pyramid_request_processing.png b/docs/_static/pyramid_request_processing.png
new file mode 100644
index 000000000..2fbb1e164
--- /dev/null
+++ b/docs/_static/pyramid_request_processing.png
Binary files differ
diff --git a/docs/_static/pyramid_request_processing.svg b/docs/_static/pyramid_request_processing.svg
new file mode 100644
index 000000000..21bbcb532
--- /dev/null
+++ b/docs/_static/pyramid_request_processing.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="91 11 424 533" width="424pt" height="533pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2014-11-23 07:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.4 --></metadata><defs><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="SharpArrow_Marker" viewBox="-4 -4 10 8" markerWidth="10" markerHeight="8" color="#191919"><g><path d="M 5 0 L -3 -3 L 0 0 L 0 0 L -3 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="10" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Request Processing</title><rect fill="white" width="576" height="733"/><g><title>no exceptions</title><path d="M 155 444.75674 C 155 450.64061 155 486.2592 155 502.71617" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 322.33334 C 154.99999 327.72413 155 337.74646 155 346.1775" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99999 245.22768 C 154.99999 250.5417 154.99999 257.93189 154.99999 265.10145" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 154.99995 198.62203 C 154.99995 203.74682 154.99998 209.1909 154.99999 215.28222" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="45.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 50.455358)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="4.7596016" y="10" textLength="88.92578">middleware ingress </tspan></text><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="96.183037" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 101.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.983723" y="10" textLength="61.69922">tween ingress</tspan></text><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="102.16667" y="222.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 227.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="28.660969" y="10" textLength="38.344727">traversal</tspan></text><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="247.18304" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 252.45536)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.424641" y="10" textLength="62.817383">ContextFound</tspan></text><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="422.2121" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 427.48442)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.094563" y="10" textLength="59.47754">tween egress</tspan></text><rect x="239" y="445.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="445.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 450.50821)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.3113594" y="10" textLength="85.043945">response callbacks</tspan></text><rect x="239" y="497.2359" width="105.666664" height="22.544641" fill="#fed153"/><rect x="239" y="497.2359" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244 502.5082)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.6463203" y="10" textLength="5">fi</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="13.64632" y="10" textLength="73.374023">nished callbacks</tspan></text><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" fill="#a4cfff"/><rect x="102.16667" y="509.61795" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 514.89027)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="5.8704414" y="10" textLength="83.92578">middleware egress</tspan></text><path d="M 155 67.72768 C 155 73.048893 155 81.55558 155 89.2853" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 155 119.22768 C 155 124.62026 154.99997 133.48763 154.99996 141.38632" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="375.5" y="391" width="105.666664" height="22.544642" fill="#dfbeff"/><rect x="375.5" y="391" width="105.666664" height="22.544642" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(380.5 396.27232)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="16.702961" y="10" textLength="62.260742">BeforeRender</tspan></text><text transform="translate(233.5 20)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".31445312" y="11" textLength="115.371094">Request Processing</tspan></text><path d="M 375.99995 42.910746 L 498.66662 42.910746 C 501.42805 42.910746 503.66662 45.149323 503.66662 47.910746 L 503.66662 222 C 503.66662 224.76142 501.42805 227 498.66662 227 L 375.99995 227 C 373.23853 227 370.99995 224.76142 370.99995 222 L 370.99995 47.910746 C 370.99995 45.149323 373.23853 42.910746 375.99995 42.910746 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(375.99995 42.910746)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="bold" x="0" y="10" textLength="35.55664">Legend</tspan></text><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="383.66662" y="63.908513" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 69.180834)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="35.601887" y="10" textLength="24.46289">event</tspan></text><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" fill="#fed153"/><rect x="383.66662" y="186.58226" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 191.85458)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="29.769367" y="10" textLength="36.12793">callback</tspan></text><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" fill="#ffff6c"/><rect x="383.66662" y="158.54998" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 163.8223)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.83089" y="10" textLength="20.004883">view</tspan></text><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" fill="#a4cfff"/><rect x="383.66662" y="91.94079" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 96.48543)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.148762" y="10" textLength="76.14746">external process </tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="2.8162422" y="22" textLength="90.03418">(middleware, tween)</tspan></text><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" fill="#d2ffd0"/><rect x="383.66662" y="130.51771" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(388.66662 135.79003)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="12.537922" y="10" textLength="70.59082">internal process</tspan></text><line x1="154.99999" y1="258.44082" x2="238.83336" y2="258.45536" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" fill="#ffff6c"/><rect x="102.16667" y="353.07515" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16667 363.61979)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.205402" y="10" textLength="57.25586">view pipeline</tspan></text><path d="M 155 386.66443 C 155 392.17252 155 405.5052 155 415.30935" marker-end="url(#SharpArrow_Marker)" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><line x1="239.33336" y1="285.57838" x2="207.66667" y2="353.07515" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><line x1="238.75001" y1="430.80676" x2="207.66667" y2="385.656" stroke="#c1c1c1" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,3"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" fill="#d2ffd0"/><rect x="102.16666" y="305.0893" width="105.666664" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 307.71132)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="24.764484" y="10" textLength="46.137695">predicates</tspan></text><rect x="102.16666" y="272" width="105.666664" height="33.089294" fill="#d2ffd0"/><rect x="102.16666" y="272" width="105.666664" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.16666 282.54465)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="21.707844" y="10" textLength="52.250977">view lookup</tspan></text><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" fill="#d2ffd0"/><rect x="102.166606" y="181.37798" width="105.666695" height="17.244049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 184)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="11.978855" y="10" textLength="71.708984">route predicates</tspan></text><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" fill="#d2ffd0"/><rect x="102.166606" y="148.28869" width="105.666695" height="33.089294" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(107.166606 158.83333)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="18.001804" y="10" textLength="20.004883">URL</tspan><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.640476" y="10" textLength="40.024414"> dispatch</tspan></text><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="239.8334" y="117.3192" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(244.8334 122.59152)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.207844" y="10" textLength="57.250977">NewRequest</tspan></text><line x1="154.99999" y1="128.68025" x2="239.8334" y2="128.59152" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" fill="#dfbeff"/><rect x="238.83336" y="471.2262" width="105.666664" height="22.544641" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 476.49852)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="15.316242" y="10" textLength="65.03418">NewResponse</tspan></text><line x1="155" y1="470.25295" x2="238.33861" y2="482.42625" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><rect x="238.75001" y="322.26348" width="105.666664" height="18.656048" fill="#ffffa3"/><rect x="238.75001" y="322.26348" width="105.666664" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 325.5915)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="1.9812813" y="10" textLength="91.7041">view mapper ingress</tspan></text><rect x="238.75001" y="341.36561" width="105.666664" height="33.089283" fill="#ffff6c"/><rect x="238.75001" y="341.36561" width="105.666664" height="33.089283" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 351.91025)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="37.83089" y="10" textLength="20.004883">view</tspan></text><rect x="238.75001" y="374.901" width="105.666664" height="18.656048" fill="#ffffa3"/><rect x="238.75001" y="374.901" width="105.666664" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 378.22901)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="3.0921211" y="10" textLength="89.48242">view mapper egress</tspan></text><rect x="238.75001" y="393.55704" width="105.666664" height="18.656048" fill="#ffffa3"/><rect x="238.75001" y="393.55704" width="105.666664" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 396.88507)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="8.9173164" y="10" textLength="77.83203">response adapter</tspan></text><rect x="238.75001" y="303.65604" width="105.666664" height="18.656048" fill="#ffffa3"/><rect x="238.75001" y="303.65604" width="105.666664" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 306.98407)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="6.702961" y="10" textLength="82.26074">decorators ingress</tspan></text><rect x="238.75001" y="412.1507" width="105.666664" height="18.656048" fill="#ffffa3"/><rect x="238.75001" y="412.1507" width="105.666664" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.75001 415.47873)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="7.813801" y="10" textLength="80.039062">decorators egress</tspan></text><rect x="238.83336" y="285" width="105.66669" height="18.656048" fill="#ffffa3"/><rect x="238.83336" y="285" width="105.66669" height="18.656048" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(243.83336 288.32802)" fill="black"><tspan font-family="Helvetica" font-size="10" font-weight="500" x="19.202972" y="10" textLength="57.260742">authorization</tspan></text><line x1="155" y1="482.12575" x2="238.52297" y2="508.3584" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="155" y1="459.27668" x2="238.50027" y2="456.52468" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/><line x1="344.41667" y1="402.88507" x2="375.5" y2="402.27232" stroke="#191919" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="1,4"/></g></g></svg>
diff --git a/docs/api/registry.rst b/docs/api/registry.rst
index bab3e26ba..57a80b3f5 100644
--- a/docs/api/registry.rst
+++ b/docs/api/registry.rst
@@ -14,6 +14,18 @@
accessed as ``request.registry.settings`` or
``config.registry.settings`` in a typical Pyramid application.
+ .. attribute:: package_name
+
+ .. versionadded:: 1.6
+
+ When a registry is set up (or created) by a :term:`Configurator`, this
+ attribute will be the shortcut for
+ :attr:`pyramid.config.Configurator.package_name`.
+
+ This attribute is often accessed as ``request.registry.package_name`` or
+ ``config.registry.package_name`` or ``config.package_name``
+ in a typical Pyramid application.
+
.. attribute:: introspector
.. versionadded:: 1.3
diff --git a/docs/api/request.rst b/docs/api/request.rst
index 77d80f6d6..dd68fa09c 100644
--- a/docs/api/request.rst
+++ b/docs/api/request.rst
@@ -167,37 +167,40 @@
.. versionadded:: 1.5
- A property which returns the userid of the currently authenticated user
- or ``None`` if there is no :term:`authentication policy` in effect or
- there is no currently authenticated user. This differs from
- :attr:`~pyramid.request.Request.unauthenticated_userid`, because the
- effective authentication policy will have ensured that a record
- associated with the userid exists in persistent storage; if it has
- not, this value will be ``None``.
+ A property which returns the :term:`userid` of the currently
+ authenticated user or ``None`` if there is no :term:`authentication
+ policy` in effect or there is no currently authenticated user. This
+ differs from :attr:`~pyramid.request.Request.unauthenticated_userid`,
+ because the effective authentication policy will have ensured that a
+ record associated with the :term:`userid` exists in persistent storage;
+ if it has not, this value will be ``None``.
.. attribute:: unauthenticated_userid
.. versionadded:: 1.5
A property which returns a value which represents the *claimed* (not
- verified) user id of the credentials present in the request. ``None`` if
- there is no :term:`authentication policy` in effect or there is no user
- data associated with the current request. This differs from
- :attr:`~pyramid.request.Request.authenticated_userid`, because the
- effective authentication policy will not ensure that a record associated
- with the userid exists in persistent storage. Even if the userid
- does not exist in persistent storage, this value will be the value
- of the userid *claimed* by the request data.
+ verified) :term:`userid` of the credentials present in the
+ request. ``None`` if there is no :term:`authentication policy` in effect
+ or there is no user data associated with the current request. This
+ differs from :attr:`~pyramid.request.Request.authenticated_userid`,
+ because the effective authentication policy will not ensure that a
+ record associated with the :term:`userid` exists in persistent storage.
+ Even if the :term:`userid` does not exist in persistent storage, this
+ value will be the value of the :term:`userid` *claimed* by the request
+ data.
.. attribute:: effective_principals
.. versionadded:: 1.5
A property which returns the list of 'effective' :term:`principal`
- identifiers for this request. This will include the userid of the
- currently authenticated user if a user is currently authenticated. If no
- :term:`authentication policy` is in effect, this will return a sequence
- containing only the :attr:`pyramid.security.Everyone` principal.
+ identifiers for this request. This list typically includes the
+ :term:`userid` of the currently authenticated user if a user is
+ currently authenticated, but this depends on the
+ :term:`authentication policy` in effect. If no :term:`authentication
+ policy` is in effect, this will return a sequence containing only the
+ :attr:`pyramid.security.Everyone` principal.
.. method:: invoke_subrequest(request, use_tweens=False)
diff --git a/docs/api/security.rst b/docs/api/security.rst
index 814b68e5a..88086dbbf 100644
--- a/docs/api/security.rst
+++ b/docs/api/security.rst
@@ -16,7 +16,7 @@ Authentication API Functions
.. autofunction:: forget
-.. autofunction:: remember
+.. autofunction:: remember(request, userid, **kwargs)
Authorization API Functions
---------------------------
diff --git a/docs/glossary.rst b/docs/glossary.rst
index ef7e9a9ae..01300a0be 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -286,13 +286,22 @@ Glossary
:term:`authorization policy`.
principal
- A *principal* is a string or unicode object representing a userid
- or a group id. It is provided by an :term:`authentication
- policy`. For example, if a user had the user id "bob", and Bob
- was part of two groups named "group foo" and "group bar", the
- request might have information attached to it that would
- indicate that Bob was represented by three principals: "bob",
- "group foo" and "group bar".
+ A *principal* is a string or unicode object representing an
+ entity, typically a user or group. Principals are provided by an
+ :term:`authentication policy`. For example, if a user had the
+ :term:`userid` `"bob"`, and was part of two groups named `"group foo"`
+ and "group bar", the request might have information attached to
+ it that would indicate that Bob was represented by three
+ principals: `"bob"`, `"group foo"` and `"group bar"`.
+
+ userid
+ A *userid* is a string or unicode object used to identify and
+ authenticate a real-world user (or client). A userid is
+ supplied to an :term:`authentication policy` in order to discover
+ the user's :term:`principals <principal>`. The default behavior
+ of the authentication policies :app:`Pyramid` provides is to
+ return the user's userid as a principal, but this is not strictly
+ necessary in custom policies that define their principals differently.
authorization policy
An authorization policy in :app:`Pyramid` terms is a bit of
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index 64dcab1d5..8c60407e5 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -15,3 +15,40 @@ class ViewTests(unittest.TestCase):
request = testing.DummyRequest()
info = my_view(request)
self.assertEqual(info['project'], 'MyProject')
+
+class ViewIntegrationTests(unittest.TestCase):
+ def setUp(self):
+ """ This sets up the application registry with the
+ registrations your application declares in its ``includeme``
+ function.
+ """
+ self.config = testing.setUp()
+ self.config.include('myproject')
+
+ def tearDown(self):
+ """ Clear out the application registry """
+ testing.tearDown()
+
+ def test_my_view(self):
+ from myproject.views import my_view
+ request = testing.DummyRequest()
+ result = my_view(request)
+ self.assertEqual(result.status, '200 OK')
+ body = result.app_iter[0]
+ self.assertTrue('Welcome to' in body)
+ self.assertEqual(len(result.headerlist), 2)
+ self.assertEqual(result.headerlist[0],
+ ('Content-Type', 'text/html; charset=UTF-8'))
+ self.assertEqual(result.headerlist[1], ('Content-Length',
+ str(len(body))))
+
+class FunctionalTests(unittest.TestCase):
+ def setUp(self):
+ from myproject import main
+ app = main({})
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue('Pyramid' in res.body)
diff --git a/docs/narr/MyProject/setup.py b/docs/narr/MyProject/setup.py
index 8c019af51..9f34540a7 100644
--- a/docs/narr/MyProject/setup.py
+++ b/docs/narr/MyProject/setup.py
@@ -1,30 +1,42 @@
-import os
+"""Setup for the MyProject package.
+"""
+import os
from setuptools import setup, find_packages
-here = os.path.abspath(os.path.dirname(__file__))
-with open(os.path.join(here, 'README.txt')) as f:
- README = f.read()
-with open(os.path.join(here, 'CHANGES.txt')) as f:
- CHANGES = f.read()
-requires = [
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+
+with open(os.path.join(HERE, 'README.txt')) as fp:
+ README = fp.read()
+
+
+with open(os.path.join(HERE, 'CHANGES.txt')) as fp:
+ CHANGES = fp.read()
+
+
+REQUIRES = [
'pyramid',
'pyramid_chameleon',
'pyramid_debugtoolbar',
'waitress',
]
+TESTS_REQUIRE = [
+ 'webtest'
+ ]
+
setup(name='MyProject',
version='0.0',
description='MyProject',
long_description=README + '\n\n' + CHANGES,
classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
author='',
author_email='',
url='',
@@ -32,11 +44,10 @@ setup(name='MyProject',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=requires,
- tests_require=requires,
- test_suite="myproject",
+ install_requires=REQUIRES,
+ tests_require=TESTS_REQUIRE,
+ test_suite='myproject',
entry_points="""\
[paste.app_factory]
main = myproject:main
- """,
- )
+ """)
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index 95863848b..fc908c2b4 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -276,15 +276,62 @@ to put static media on a separate webserver during production (if the
``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is
a URL), while keeping static media package-internal and served by the
development webserver during development (if the ``name`` argument to
-:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). To
-create such a circumstance, we suggest using the
-:attr:`pyramid.registry.Registry.settings` API in conjunction with a setting
-in the application ``.ini`` file named ``media_location``. Then set the
-value of ``media_location`` to either a prefix or a URL depending on whether
-the application is being run in development or in production (use a different
-``.ini`` file for production than you do for development). This is just a
-suggestion for a pattern; any setting name other than ``media_location``
-could be used.
+:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix).
+
+For example, we may define a :ref:`custom setting <adding_a_custom_setting>`
+named ``media_location`` which we can set to an external URL in production
+when our assets are hosted on a CDN.
+
+.. code-block:: python
+ :linenos:
+
+ media_location = settings.get('media_location', 'static')
+
+ config = Configurator(settings=settings)
+ config.add_static_view(path='myapp:static', name=media_location)
+
+Now we can optionally define the setting in our ini file:
+
+.. code-block:: ini
+ :linenos:
+
+ # production.ini
+ [app:main]
+ use = egg:myapp#main
+
+ media_location = http://static.example.com/
+
+It is also possible to serve assets that live outside of the source by
+referring to an absolute path on the filesystem. There are two ways to
+accomplish this.
+
+First, :meth:`~pyramid.config.Configurator.add_static_view`
+supports taking an absolute path directly instead of an asset spec. This works
+as expected, looking in the file or folder of files and serving them up at
+some URL within your application or externally. Unfortunately, this technique
+has a drawback that it is not possible to use the
+:meth:`~pyramid.request.Request.static_url` method to generate URLs, since it
+works based on an asset spec.
+
+The second approach, available in Pyramid 1.6+, uses the asset overriding
+APIs described in the :ref:`overriding_assets_section` section. It is then
+possible to configure a "dummy" package which then serves its file or folder
+from an absolute path.
+
+.. code-block:: python
+
+ config.add_static_view(path='myapp:static_images', name='static')
+ config.override_asset(to_override='myapp:static_images/',
+ override_with='/abs/path/to/images/')
+
+From this configuration it is now possible to use
+:meth:`~pyramid.request.Request.static_url` to generate URLs to the data
+in the folder by doing something like
+``request.static_url('myapp:static_images/foo.png')``. While it is not
+necessary that the ``static_images`` file or folder actually exist in the
+``myapp`` package, it is important that the ``myapp`` portion points to a
+valid package. If the folder does exist then the overriden folder is given
+priority if the file's name exists in both locations.
.. index::
single: Cache Busting
@@ -701,3 +748,6 @@ files. Any software which uses the
:func:`pkg_resources.get_resource_string` APIs will obtain an overridden file
when an override is used.
+As of Pyramid 1.6, it is also possible to override an asset by supplying an
+absolute path to a file or directory. This may be useful if the assets are
+not distributed as part of a Python package.
diff --git a/docs/narr/router.rst b/docs/narr/router.rst
index ac3deefdc..e82b66801 100644
--- a/docs/narr/router.rst
+++ b/docs/narr/router.rst
@@ -9,6 +9,9 @@
Request Processing
==================
+.. image:: ../_static/pyramid_request_processing.svg
+ :alt: Request Processing
+
Once a :app:`Pyramid` application is up and running, it is ready to accept
requests and return responses. What happens from the time a :term:`WSGI`
request enters a :app:`Pyramid` application through to the point that
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 8db23a33b..2dc0c76af 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,13 +6,28 @@
Security
========
-:app:`Pyramid` provides an optional declarative authorization system
-that can prevent a :term:`view` from being invoked based on an
+:app:`Pyramid` provides an optional, declarative, security system.
+Security in :app:`Pyramid` is separated into authentication and
+authorization. The two systems communicate via :term:`principal`
+identifiers. Authentication is merely the mechanism by which credentials
+provided in the :term:`request` are resolved to one or more
+:term:`principal` identifiers. These identifiers represent the users and
+groups that are in effect during the request. Authorization then determines
+access based on the :term:`principal` identifiers, the requested
+:term:`permission`, and a :term:`context`.
+
+The :app:`Pyramid` authorization system
+can prevent a :term:`view` from being invoked based on an
:term:`authorization policy`. Before a view is invoked, the
authorization system can use the credentials in the :term:`request`
along with the :term:`context` resource to determine if access will be
allowed. Here's how it works at a high level:
+- A user may or may not have previously visited the application and
+ supplied authentication credentials, including a :term:`userid`. If
+ so, the application may have called
+ :func:`pyramid.security.remember` to remember these.
+
- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
@@ -25,7 +40,9 @@ allowed. Here's how it works at a high level:
context as well as other attributes of the request.
- If an :term:`authentication policy` is in effect, it is passed the
- request; it returns some number of :term:`principal` identifiers.
+ request. It will return some number of :term:`principal` identifiers.
+ To do this, the policy would need to determine the authenticated
+ :term:`userid` present in the request.
- If an :term:`authorization policy` is in effect and the :term:`view
configuration` associated with the view callable that was found has
@@ -41,15 +58,6 @@ allowed. Here's how it works at a high level:
- If the authorization policy denies access, the view callable is not
invoked; instead the :term:`forbidden view` is invoked.
-Security in :app:`Pyramid`, unlike many systems, cleanly and explicitly
-separates authentication and authorization. Authentication is merely the
-mechanism by which credentials provided in the :term:`request` are
-resolved to one or more :term:`principal` identifiers. These identifiers
-represent the users and groups in effect during the request.
-Authorization then determines access based on the :term:`principal`
-identifiers, the :term:`view callable` being invoked, and the
-:term:`context` resource.
-
Authorization is enabled by modifying your application to include an
:term:`authentication policy` and :term:`authorization policy`.
:app:`Pyramid` comes with a variety of implementations of these
@@ -104,7 +112,8 @@ For example:
The above configuration enables a policy which compares the value of an "auth
ticket" cookie passed in the request's environment which contains a reference
-to a single :term:`principal` against the principals present in any
+to a single :term:`userid` and matches that userid's
+:term:`principals <principal>` against the principals present in any
:term:`ACL` found in the resource tree when attempting to call some
:term:`view`.
@@ -595,36 +604,53 @@ that implements the following interface:
""" An object representing a Pyramid authentication policy. """
def authenticated_userid(self, request):
- """ Return the authenticated userid or ``None`` if no
- authenticated userid can be found. This method of the policy
- should ensure that a record exists in whatever persistent store is
- used related to the user (the user should not have been deleted);
- if a record associated with the current id does not exist in a
- persistent store, it should return ``None``."""
+ """ Return the authenticated :term:`userid` or ``None`` if
+ no authenticated userid can be found. This method of the
+ policy should ensure that a record exists in whatever
+ persistent store is used related to the user (the user
+ should not have been deleted); if a record associated with
+ the current id does not exist in a persistent store, it
+ should return ``None``.
+
+ """
def unauthenticated_userid(self, request):
- """ Return the *unauthenticated* userid. This method performs the
- same duty as ``authenticated_userid`` but is permitted to return the
- userid based only on data present in the request; it needn't (and
- shouldn't) check any persistent store to ensure that the user record
- related to the request userid exists."""
+ """ Return the *unauthenticated* userid. This method
+ performs the same duty as ``authenticated_userid`` but is
+ permitted to return the userid based only on data present
+ in the request; it needn't (and shouldn't) check any
+ persistent store to ensure that the user record related to
+ the request userid exists.
+
+ This method is intended primarily a helper to assist the
+ ``authenticated_userid`` method in pulling credentials out
+ of the request data, abstracting away the specific headers,
+ query strings, etc that are used to authenticate the request.
+
+ """
def effective_principals(self, request):
""" Return a sequence representing the effective principals
- including the userid and any groups belonged to by the current
- user, including 'system' groups such as
- ``pyramid.security.Everyone`` and
- ``pyramid.security.Authenticated``. """
+ typically including the :term:`userid` and any groups belonged
+ to by the current user, always including 'system' groups such
+ as ``pyramid.security.Everyone`` and
+ ``pyramid.security.Authenticated``.
- def remember(self, request, principal, **kw):
+ """
+
+ def remember(self, request, userid, **kw):
""" Return a set of headers suitable for 'remembering' the
- principal named ``principal`` when set in a response. An
- individual authentication policy and its consumers can decide
- on the composition and meaning of **kw. """
-
+ :term:`userid` named ``userid`` when set in a response. An
+ individual authentication policy and its consumers can
+ decide on the composition and meaning of **kw.
+
+ """
+
def forget(self, request):
""" Return a set of headers suitable for 'forgetting' the
- current user on subsequent requests. """
+ current user on subsequent requests.
+
+ """
After you do so, you can pass an instance of such a class into the
:class:`~pyramid.config.Configurator.set_authentication_policy` method
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index e001ad81c..ecda57489 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -128,8 +128,9 @@ functions accepts various arguments that influence the environment of the
test. See the :ref:`testing_module` API for information about the extra
arguments supported by these functions.
-If you also want to make :func:`~pyramid.threadlocal.get_current_request` return something
-other than ``None`` during the course of a single test, you can pass a
+If you also want to make :func:`~pyramid.threadlocal.get_current_request`
+return something other than ``None`` during the course of a single test, you
+can pass a
:term:`request` object into the :func:`pyramid.testing.setUp` within the
``setUp`` method of your test:
@@ -333,66 +334,49 @@ Creating Integration Tests
--------------------------
In :app:`Pyramid`, a *unit test* typically relies on "mock" or "dummy"
-implementations to give the code under test only enough context to run.
+implementations to give the code under test enough context to run.
"Integration testing" implies another sort of testing. In the context of a
-:app:`Pyramid` integration test, the test logic tests the functionality of
-some code *and* its integration with the rest of the :app:`Pyramid`
+:app:`Pyramid` integration test, the test logic exercises the functionality of
+the code under test *and* its integration with the rest of the :app:`Pyramid`
framework.
-In :app:`Pyramid` applications that are plugins to Pyramid, you can create an
-integration test by including its ``includeme`` function via
-:meth:`pyramid.config.Configurator.include` in the test's setup code. This
-causes the entire :app:`Pyramid` environment to be set up and torn down as if
-your application was running "for real". This is a heavy-hammer way of
-making sure that your tests have enough context to run properly, and it tests
-your code's integration with the rest of :app:`Pyramid`.
+Creating an integration test for a :app:`Pyramid` application usually means
+invoking the application's ``includeme`` function via
+:meth:`pyramid.config.Configurator.include` within the test's setup code. This
+causes the entire :app:`Pyramid` environment to be set up, simulating what
+happens when your application is run "for real". This is a heavy-hammer way of
+making sure that your tests have enough context to run properly, and tests your
+code's integration with the rest of :app:`Pyramid`.
-Let's demonstrate this by showing an integration test for a view. The below
-test assumes that your application's package name is ``myapp``, and that
-there is a ``views`` module in the app with a function with the name
-``my_view`` in it that returns the response 'Welcome to this application'
-after accessing some values that require a fully set up environment.
+.. seealso::
-.. code-block:: python
- :linenos:
+ See also :ref:`including_configuration`
- import unittest
+Let's demonstrate this by showing an integration test for a view.
- from pyramid import testing
+Given the following view definition, which assumes that your application's
+:term:`package` name is ``myproject``, and within that :term:`package` there
+exists a module ``views``, which in turn contains a :term:`view` function named
+``my_view``:
- class ViewIntegrationTests(unittest.TestCase):
- def setUp(self):
- """ This sets up the application registry with the
- registrations your application declares in its ``includeme``
- function.
- """
- import myapp
- self.config = testing.setUp()
- self.config.include('myapp')
+ .. literalinclude:: MyProject/myproject/views.py
+ :linenos:
+ :lines: 1-6
+ :language: python
- def tearDown(self):
- """ Clear out the application registry """
- testing.tearDown()
+You'd then create a ``tests`` module within your ``myproject`` package,
+containing the following test code:
- def test_my_view(self):
- from myapp.views import my_view
- request = testing.DummyRequest()
- result = my_view(request)
- self.assertEqual(result.status, '200 OK')
- body = result.app_iter[0]
- self.assertTrue('Welcome to' in body)
- self.assertEqual(len(result.headerlist), 2)
- self.assertEqual(result.headerlist[0],
- ('Content-Type', 'text/html; charset=UTF-8'))
- self.assertEqual(result.headerlist[1], ('Content-Length',
- str(len(body))))
-
-Unless you cannot avoid it, you should prefer writing unit tests that use the
-:class:`~pyramid.config.Configurator` API to set up the right "mock"
-registrations rather than creating an integration test. Unit tests will run
-faster (because they do less for each test) and the result of a unit test is
-usually easier to make assertions about.
+ .. literalinclude:: MyProject/myproject/tests.py
+ :linenos:
+ :pyobject: ViewIntegrationTests
+ :language: python
+
+Writing unit tests that use the :class:`~pyramid.config.Configurator` API to
+set up the right "mock" registrations is often preferred to creating
+integration tests. Unit tests will run faster (because they do less for each
+test) and are usually easier to reason about.
.. index::
single: functional tests
@@ -404,34 +388,40 @@ Creating Functional Tests
Functional tests test your literal application.
-The below test assumes that your application's package name is ``myapp``, and
-that there is a view that returns an HTML body when the root URL is invoked.
-It further assumes that you've added a ``tests_require`` dependency on the
-``WebTest`` package within your ``setup.py`` file. :term:`WebTest` is a
-functional testing package written by Ian Bicking.
+In Pyramid, functional tests are typically written using the :term:`WebTest`
+package, which provides APIs for invoking HTTP(S) requests to your application.
-.. code-block:: python
- :linenos:
+Regardless of which testing :term:`package` you use, ensure to add a
+``tests_require`` dependency on that package to to your application's
+``setup.py`` file:
- import unittest
+ .. literalinclude:: MyProject/setup.py
+ :linenos:
+ :emphasize-lines: 26-28,48
+ :language: python
- class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from myapp import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue('Pyramid' in res.body)
-
-When this test is run, each test creates a "real" WSGI application using the
-``main`` function in your ``myapp.__init__`` module and uses :term:`WebTest`
-to wrap that WSGI application. It assigns the result to ``self.testapp``.
-In the test named ``test_root``, we use the testapp's ``get`` method to
-invoke the root URL. We then assert that the returned HTML has the string
-``Pyramid`` in it.
+Assuming your :term:`package` is named ``myproject``, which contains a
+``views`` module, which in turn contains a :term:`view` function ``my_view``
+that returns a HTML body when the root URL is invoked:
+
+ .. literalinclude:: MyProject/myproject/views.py
+ :linenos:
+ :language: python
+
+Then the following example functional test (shown below) demonstrates invoking
+the :term:`view` shown above:
+
+ .. literalinclude:: MyProject/myproject/tests.py
+ :linenos:
+ :pyobject: FunctionalTests
+ :language: python
+
+When this test is run, each test method creates a "real" :term:`WSGI`
+application using the ``main`` function in your ``myproject.__init__`` module,
+using :term:`WebTest` to wrap that WSGI application. It assigns the result to
+``self.testapp``. In the test named ``test_root``. The ``TestApp``'s ``get``
+method is used to invoke the root URL. Finally, an assertion is made that the
+returned HTML contains the text ``MyProject``.
See the :term:`WebTest` documentation for further information about the
methods available to a :class:`webtest.app.TestApp` instance.
diff --git a/docs/tutorials/wiki/design.rst b/docs/tutorials/wiki/design.rst
index eb785dd1c..28380bd66 100644
--- a/docs/tutorials/wiki/design.rst
+++ b/docs/tutorials/wiki/design.rst
@@ -53,10 +53,10 @@ Security
We'll eventually be adding security to our application. The components we'll
use to do this are below.
-- USERS, a dictionary mapping usernames to their
+- USERS, a dictionary mapping :term:`userids <userid>` to their
corresponding passwords.
-- GROUPS, a dictionary mapping usernames to a
+- GROUPS, a dictionary mapping :term:`userids <userid>` to a
list of groups to which they belong to.
- ``groupfinder``, an *authorization callback* that looks up
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
index df2c83398..ff7413668 100644
--- a/docs/tutorials/wiki2/design.rst
+++ b/docs/tutorials/wiki2/design.rst
@@ -53,7 +53,8 @@ Security
We'll eventually be adding security to our application. The components we'll
use to do this are below.
-- USERS, a dictionary mapping users names to their corresponding passwords.
+- USERS, a dictionary mapping users names (the user's :term:`userids
+ <userid>`) to their corresponding passwords.
- GROUPS, a dictionary mapping user names to a list of groups they belong to.
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index b84981bbc..e0e241e52 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -3,7 +3,6 @@ from codecs import utf_8_decode
from codecs import utf_8_encode
import hashlib
import base64
-import datetime
import re
import time as time_mod
import warnings
@@ -335,11 +334,11 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
effective_principals.extend(groups)
return effective_principals
- def remember(self, request, principal, **kw):
- """ Store the ``principal`` as ``repoze.who.userid``.
+ def remember(self, request, userid, **kw):
+ """ Store the ``userid`` as ``repoze.who.userid``.
The identity to authenticated to :mod:`repoze.who`
- will contain the given principal as ``userid``, and
+ will contain the given userid as ``userid``, and
provide all keyword arguments as additional identity
keys. Useful keys could be ``max_age`` or ``userdata``.
"""
@@ -348,7 +347,7 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
return []
environ = request.environ
identity = kw
- identity['repoze.who.userid'] = principal
+ identity['repoze.who.userid'] = userid
return identifier.remember(environ, identity)
def forget(self, request):
@@ -404,7 +403,7 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy):
""" The ``REMOTE_USER`` value found within the ``environ``."""
return request.environ.get(self.environ_key)
- def remember(self, request, principal, **kw):
+ def remember(self, request, userid, **kw):
""" A no-op. The ``REMOTE_USER`` does not provide a protocol for
remembering the user. This will be application-specific and can
be done somewhere else or in a subclass."""
@@ -652,7 +651,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
if result:
return result['userid']
- def remember(self, request, principal, **kw):
+ def remember(self, request, userid, **kw):
""" Accepts the following kw args: ``max_age=<int-seconds>,
``tokens=<sequence-of-ascii-strings>``.
@@ -660,7 +659,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
the response.
"""
- return self.cookie.remember(request, principal, **kw)
+ return self.cookie.remember(request, userid, **kw)
def forget(self, request):
""" A list of headers which will delete appropriate cookies."""
@@ -741,7 +740,7 @@ def parse_ticket(secret, ticket, ip, hashalg='md5'):
If the ticket cannot be parsed, a ``BadTicket`` exception will be raised
with an explanation.
"""
- ticket = ticket.strip('"')
+ ticket = native_(ticket).strip('"')
digest_size = hashlib.new(hashalg).digest_size * 2
digest = ticket[:digest_size]
try:
@@ -929,7 +928,7 @@ class AuthTktCookieHelper(object):
if reissue and not hasattr(request, '_authtkt_reissued'):
if ( (now - timestamp) > self.reissue_time ):
- # work around https://github.com/Pylons/pyramid/issues#issue/108
+ # See https://github.com/Pylons/pyramid/issues#issue/108
tokens = list(filter(None, tokens))
headers = self.remember(request, userid, max_age=self.max_age,
tokens=tokens)
@@ -1061,13 +1060,13 @@ class SessionAuthenticationPolicy(CallbackAuthenticationPolicy):
self.userid_key = prefix + 'userid'
self.debug = debug
- def remember(self, request, principal, **kw):
- """ Store a principal in the session."""
- request.session[self.userid_key] = principal
+ def remember(self, request, userid, **kw):
+ """ Store a userid in the session."""
+ request.session[self.userid_key] = userid
return []
def forget(self, request):
- """ Remove the stored principal from the session."""
+ """ Remove the stored userid from the session."""
if self.userid_key in request.session:
del request.session[self.userid_key]
return []
@@ -1132,7 +1131,7 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy):
if credentials:
return credentials[0]
- def remember(self, request, principal, **kw):
+ def remember(self, request, userid, **kw):
""" A no-op. Basic authentication does not provide a protocol for
remembering the user. Credentials are sent on every request.
diff --git a/pyramid/config/assets.py b/pyramid/config/assets.py
index 0616e6cda..9da092f08 100644
--- a/pyramid/config/assets.py
+++ b/pyramid/config/assets.py
@@ -1,3 +1,4 @@
+import os
import pkg_resources
import sys
@@ -79,7 +80,8 @@ class OverrideProvider(pkg_resources.DefaultProvider):
return result
return pkg_resources.DefaultProvider.resource_listdir(
self, resource_name)
-
+
+
@implementer(IPackageOverrides)
class PackageOverrides(object):
# pkg_resources arg in kw args below for testing
@@ -97,57 +99,61 @@ class PackageOverrides(object):
# optional)...
# A __loader__ attribute is basically metadata, and setuptools
# uses it as such.
- package.__loader__ = self
+ package.__loader__ = self
# we call register_loader_type for every instantiation of this
# class; that's OK, it's idempotent to do it more than once.
pkg_resources.register_loader_type(self.__class__, OverrideProvider)
self.overrides = []
self.overridden_package_name = package.__name__
- def insert(self, path, package, prefix):
+ def insert(self, path, source):
if not path or path.endswith('/'):
- override = DirectoryOverride(path, package, prefix)
+ override = DirectoryOverride(path, source)
else:
- override = FileOverride(path, package, prefix)
+ override = FileOverride(path, source)
self.overrides.insert(0, override)
return override
- def search_path(self, resource_name):
+ def filtered_sources(self, resource_name):
for override in self.overrides:
o = override(resource_name)
if o is not None:
- package, name = o
- yield package, name
+ yield o
def get_filename(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
- return pkg_resources.resource_filename(package, rname)
+ for source, path in self.filtered_sources(resource_name):
+ result = source.get_filename(path)
+ if result is not None:
+ return result
def get_stream(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
- return pkg_resources.resource_stream(package, rname)
+ for source, path in self.filtered_sources(resource_name):
+ result = source.get_stream(path)
+ if result is not None:
+ return result
def get_string(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
- return pkg_resources.resource_string(package, rname)
+ for source, path in self.filtered_sources(resource_name):
+ result = source.get_string(path)
+ if result is not None:
+ return result
def has_resource(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
+ for source, path in self.filtered_sources(resource_name):
+ if source.exists(path):
return True
def isdir(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
- return pkg_resources.resource_isdir(package, rname)
+ for source, path in self.filtered_sources(resource_name):
+ result = source.isdir(path)
+ if result is not None:
+ return result
def listdir(self, resource_name):
- for package, rname in self.search_path(resource_name):
- if pkg_resources.resource_exists(package, rname):
- return pkg_resources.resource_listdir(package, rname)
+ for source, path in self.filtered_sources(resource_name):
+ result = source.listdir(path)
+ if result is not None:
+ return result
@property
def real_loader(self):
@@ -174,72 +180,180 @@ class PackageOverrides(object):
""" See IPEP302Loader.
"""
return self.real_loader.get_source(fullname)
-
+
class DirectoryOverride:
- def __init__(self, path, package, prefix):
+ def __init__(self, path, source):
self.path = path
- self.package = package
- self.prefix = prefix
self.pathlen = len(self.path)
+ self.source = source
def __call__(self, resource_name):
if resource_name.startswith(self.path):
- name = '%s%s' % (self.prefix, resource_name[self.pathlen:])
- return self.package, name
+ new_path = resource_name[self.pathlen:]
+ return self.source, new_path
class FileOverride:
- def __init__(self, path, package, prefix):
+ def __init__(self, path, source):
self.path = path
- self.package = package
- self.prefix = prefix
+ self.source = source
def __call__(self, resource_name):
if resource_name == self.path:
- return self.package, self.prefix
+ return self.source, ''
+
+
+class PackageAssetSource(object):
+ """
+ An asset source relative to a package.
+
+ If this asset source is a file, then we expect the ``prefix`` to point
+ to the new name of the file, and the incoming ``resource_name`` will be
+ the empty string, as returned by the ``FileOverride``.
+
+ """
+ def __init__(self, package, prefix):
+ self.package = package
+ self.prefix = prefix
+
+ def get_path(self, resource_name):
+ return '%s%s' % (self.prefix, resource_name)
+
+ def get_filename(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return pkg_resources.resource_filename(self.package, path)
+
+ def get_stream(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return pkg_resources.resource_stream(self.package, path)
+
+ def get_string(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return pkg_resources.resource_string(self.package, path)
+
+ def exists(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return True
+
+ def isdir(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return pkg_resources.resource_isdir(self.package, path)
+
+ def listdir(self, resource_name):
+ path = self.get_path(resource_name)
+ if pkg_resources.resource_exists(self.package, path):
+ return pkg_resources.resource_listdir(self.package, path)
+
+
+class FSAssetSource(object):
+ """
+ An asset source relative to a path in the filesystem.
+
+ """
+ def __init__(self, prefix):
+ self.prefix = prefix
+
+ def get_filename(self, resource_name):
+ if resource_name:
+ path = os.path.join(self.prefix, resource_name)
+ else:
+ path = self.prefix
+
+ if os.path.exists(path):
+ return path
+
+ def get_stream(self, resource_name):
+ path = self.get_filename(resource_name)
+ if path is not None:
+ return open(path, 'rb')
+
+ def get_string(self, resource_name):
+ stream = self.get_stream(resource_name)
+ if stream is not None:
+ with stream:
+ return stream.read()
+
+ def exists(self, resource_name):
+ path = self.get_filename(resource_name)
+ if path is not None:
+ return True
+
+ def isdir(self, resource_name):
+ path = self.get_filename(resource_name)
+ if path is not None:
+ return os.path.isdir(path)
+
+ def listdir(self, resource_name):
+ path = self.get_filename(resource_name)
+ if path is not None:
+ return os.listdir(path)
class AssetsConfiguratorMixin(object):
- def _override(self, package, path, override_package, override_prefix,
+ def _override(self, package, path, override_source,
PackageOverrides=PackageOverrides):
pkg_name = package.__name__
- override_pkg_name = override_package.__name__
override = self.registry.queryUtility(IPackageOverrides, name=pkg_name)
if override is None:
override = PackageOverrides(package)
self.registry.registerUtility(override, IPackageOverrides,
name=pkg_name)
- override.insert(path, override_pkg_name, override_prefix)
+ override.insert(path, override_source)
@action_method
def override_asset(self, to_override, override_with, _override=None):
""" Add a :app:`Pyramid` asset override to the current
configuration state.
- ``to_override`` is a :term:`asset specification` to the
+ ``to_override`` is an :term:`asset specification` to the
asset being overridden.
- ``override_with`` is a :term:`asset specification` to the
- asset that is performing the override.
+ ``override_with`` is an :term:`asset specification` to the
+ asset that is performing the override. This may also be an absolute
+ path.
See :ref:`assets_chapter` for more
information about asset overrides."""
if to_override == override_with:
- raise ConfigurationError('You cannot override an asset with itself')
+ raise ConfigurationError(
+ 'You cannot override an asset with itself')
package = to_override
path = ''
if ':' in to_override:
package, path = to_override.split(':', 1)
- override_package = override_with
- override_prefix = ''
- if ':' in override_with:
- override_package, override_prefix = override_with.split(':', 1)
-
# *_isdir = override is package or directory
- overridden_isdir = path=='' or path.endswith('/')
- override_isdir = override_prefix=='' or override_prefix.endswith('/')
+ overridden_isdir = path == '' or path.endswith('/')
+
+ if os.path.isabs(override_with):
+ override_source = FSAssetSource(override_with)
+ if not os.path.exists(override_with):
+ raise ConfigurationError(
+ 'Cannot override asset with an absolute path that does '
+ 'not exist')
+ override_isdir = os.path.isdir(override_with)
+ override_package = None
+ override_prefix = override_with
+ else:
+ override_package = override_with
+ override_prefix = ''
+ if ':' in override_with:
+ override_package, override_prefix = override_with.split(':', 1)
+
+ __import__(override_package)
+ to_package = sys.modules[override_package]
+ override_source = PackageAssetSource(to_package, override_prefix)
+
+ override_isdir = (
+ override_prefix == '' or
+ override_with.endswith('/')
+ )
if overridden_isdir and (not override_isdir):
raise ConfigurationError(
@@ -255,10 +369,8 @@ class AssetsConfiguratorMixin(object):
def register():
__import__(package)
- __import__(override_package)
from_package = sys.modules[package]
- to_package = sys.modules[override_package]
- override(from_package, path, to_package, override_prefix)
+ override(from_package, path, override_source)
intr = self.introspectable(
'asset overrides',
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index e4171b0c5..c01b72e12 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -1186,10 +1186,6 @@ class ViewsConfiguratorMixin(object):
predlist = self.get_predlist('view')
def register(permission=permission, renderer=renderer):
- # the discrim_func above is guaranteed to have been called already
- order = view_intr['order']
- preds = view_intr['predicates']
- phash = view_intr['phash']
request_iface = IRequest
if route_name is not None:
request_iface = self.registry.queryUtility(IRouteRequest,
@@ -1955,7 +1951,7 @@ class StaticURLInfo(object):
sep = os.sep
else:
sep = '/'
- if not spec.endswith(sep):
+ if not spec.endswith(sep) and not spec.endswith(':'):
spec = spec + sep
# we also make sure the name ends with a slash, purely as a
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index c5a70dbfd..b21c6b9cc 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -439,36 +439,55 @@ class IViewMapperFactory(Interface):
class IAuthenticationPolicy(Interface):
""" An object representing a Pyramid authentication policy. """
+
def authenticated_userid(request):
- """ Return the authenticated userid or ``None`` if no authenticated
- userid can be found. This method of the policy should ensure that a
- record exists in whatever persistent store is used related to the
- user (the user should not have been deleted); if a record associated
- with the current id does not exist in a persistent store, it should
- return ``None``."""
+ """ Return the authenticated :term:`userid` or ``None`` if
+ no authenticated userid can be found. This method of the
+ policy should ensure that a record exists in whatever
+ persistent store is used related to the user (the user
+ should not have been deleted); if a record associated with
+ the current id does not exist in a persistent store, it
+ should return ``None``.
+
+ """
def unauthenticated_userid(request):
- """ Return the *unauthenticated* userid. This method performs the
- same duty as ``authenticated_userid`` but is permitted to return the
- userid based only on data present in the request; it needn't (and
- shouldn't) check any persistent store to ensure that the user record
- related to the request userid exists."""
+ """ Return the *unauthenticated* userid. This method
+ performs the same duty as ``authenticated_userid`` but is
+ permitted to return the userid based only on data present
+ in the request; it needn't (and shouldn't) check any
+ persistent store to ensure that the user record related to
+ the request userid exists.
+
+ This method is intended primarily a helper to assist the
+ ``authenticated_userid`` method in pulling credentials out
+ of the request data, abstracting away the specific headers,
+ query strings, etc that are used to authenticate the request.
+
+ """
def effective_principals(request):
""" Return a sequence representing the effective principals
- including the userid and any groups belonged to by the current
- user, including 'system' groups such as Everyone and
- Authenticated. """
+ typically including the :term:`userid` and any groups belonged
+ to by the current user, always including 'system' groups such
+ as ``pyramid.security.Everyone`` and
+ ``pyramid.security.Authenticated``.
- def remember(request, principal, **kw):
+ """
+
+ def remember(request, userid, **kw):
""" Return a set of headers suitable for 'remembering' the
- principal named ``principal`` when set in a response. An
- individual authentication policy and its consumers can decide
- on the composition and meaning of ``**kw.`` """
+ :term:`userid` named ``userid`` when set in a response. An
+ individual authentication policy and its consumers can
+ decide on the composition and meaning of ``**kw``.
+
+ """
def forget(request):
""" Return a set of headers suitable for 'forgetting' the
- current user on subsequent requests. """
+ current user on subsequent requests.
+
+ """
class IAuthorizationPolicy(Interface):
""" An object representing a Pyramid authorization policy. """
diff --git a/pyramid/registry.py b/pyramid/registry.py
index 606251a8d..8c05940b9 100644
--- a/pyramid/registry.py
+++ b/pyramid/registry.py
@@ -5,6 +5,7 @@ from zope.interface import implementer
from zope.interface.registry import Components
from pyramid.compat import text_
+from pyramid.decorator import reify
from pyramid.interfaces import (
ISettings,
@@ -42,6 +43,10 @@ class Registry(Components, dict):
# defeat bool determination via dict.__len__
return True
+ @reify
+ def package_name(self):
+ return self.__name__
+
def registerSubscriptionAdapter(self, *arg, **kw):
result = Components.registerSubscriptionAdapter(self, *arg, **kw)
self.has_listeners = True
diff --git a/pyramid/scripts/proutes.py b/pyramid/scripts/proutes.py
index 5784026bb..d0c1aa13e 100644
--- a/pyramid/scripts/proutes.py
+++ b/pyramid/scripts/proutes.py
@@ -5,10 +5,15 @@ import textwrap
from pyramid.paster import bootstrap
from pyramid.scripts.common import parse_vars
+
+PAD = 3
+
+
def main(argv=sys.argv, quiet=False):
command = PRoutesCommand(argv, quiet)
return command.run()
+
class PRoutesCommand(object):
description = """\
Print all URL dispatch routes used by a Pyramid application in the
@@ -43,7 +48,7 @@ class PRoutesCommand(object):
def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
-
+
def run(self, quiet=False):
if not self.args:
self.out('requires a config file argument')
@@ -52,6 +57,8 @@ class PRoutesCommand(object):
from pyramid.interfaces import IRouteRequest
from pyramid.interfaces import IViewClassifier
from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+
from zope.interface import Interface
config_uri = self.args[0]
@@ -59,13 +66,23 @@ class PRoutesCommand(object):
registry = env['registry']
mapper = self._get_mapper(registry)
if mapper is not None:
+ mapped_routes = [('Name', 'Pattern', 'View')]
+
+ max_name = len('Name')
+ max_pattern = len('Pattern')
+ max_view = len('View')
+
routes = mapper.get_routes()
- fmt = '%-15s %-30s %-25s'
+
if not routes:
return 0
- self.out(fmt % ('Name', 'Pattern', 'View'))
- self.out(
- fmt % ('-'*len('Name'), '-'*len('Pattern'), '-'*len('View')))
+
+ mapped_routes.append((
+ '-' * max_name,
+ '-' * max_pattern,
+ '-' * max_view,
+ ))
+
for route in routes:
pattern = route.pattern
if not pattern.startswith('/'):
@@ -73,13 +90,50 @@ class PRoutesCommand(object):
request_iface = registry.queryUtility(IRouteRequest,
name=route.name)
view_callable = None
+
if (request_iface is None) or (route.factory is not None):
- self.out(fmt % (route.name, pattern, '<unknown>'))
+ view_callable = '<unknown>'
else:
view_callable = registry.adapters.lookup(
(IViewClassifier, request_iface, Interface),
IView, name='', default=None)
- self.out(fmt % (route.name, pattern, view_callable))
+
+ if view_callable is not None:
+ if IMultiView.providedBy(view_callable):
+ view_callables = [
+ x[1] for x in view_callable.views
+ ]
+ else:
+ view_callables = [view_callable]
+
+ for view_func in view_callables:
+ view_callable = '%s.%s' % (
+ view_func.__module__,
+ view_func.__name__,
+ )
+ else:
+ view_callable = str(None)
+
+ if len(route.name) > max_name:
+ max_name = len(route.name)
+
+ if len(pattern) > max_pattern:
+ max_pattern = len(pattern)
+
+ if len(view_callable) > max_view:
+ max_view = len(view_callable)
+
+ mapped_routes.append((route.name, pattern, view_callable))
+
+ fmt = '%-{0}s %-{1}s %-{2}s'.format(
+ max_name + PAD,
+ max_pattern + PAD,
+ max_view + PAD,
+ )
+
+ for route_data in mapped_routes:
+ self.out(fmt % route_data)
+
return 0
if __name__ == '__main__': # pragma: no cover
diff --git a/pyramid/scripts/pshell.py b/pyramid/scripts/pshell.py
index 12b078677..1168ba78a 100644
--- a/pyramid/scripts/pshell.py
+++ b/pyramid/scripts/pshell.py
@@ -1,9 +1,11 @@
from code import interact
import optparse
+import os
import sys
import textwrap
from pyramid.compat import configparser
+from pyramid.compat import exec_
from pyramid.util import DottedNameResolver
from pyramid.paster import bootstrap
@@ -51,6 +53,7 @@ class PShellCommand(object):
loaded_objects = {}
object_help = {}
setup = None
+ pystartup = os.environ.get('PYTHONSTARTUP')
def __init__(self, argv, quiet=False):
self.quiet = quiet
@@ -144,6 +147,12 @@ class PShellCommand(object):
if shell is None:
shell = self.make_shell()
+ if self.pystartup and os.path.isfile(self.pystartup):
+ with open(self.pystartup, 'rb') as fp:
+ exec_(fp.read().decode('utf-8'), env)
+ if '__builtins__' in env:
+ del env['__builtins__']
+
try:
shell(env, help)
finally:
diff --git a/pyramid/security.py b/pyramid/security.py
index 041155563..cbb4b895f 100644
--- a/pyramid/security.py
+++ b/pyramid/security.py
@@ -17,6 +17,8 @@ Authenticated = 'system.Authenticated'
Allow = 'Allow'
Deny = 'Deny'
+_marker = object()
+
class AllPermissionsList(object):
""" Stand in 'permission list' to represent all permissions """
def __iter__(self):
@@ -115,12 +117,12 @@ deprecated(
'"effective_principals" attribute of the Pyramid request instead.'
)
-def remember(request, principal, **kw):
+def remember(request, userid=_marker, **kw):
"""
Returns a sequence of header tuples (e.g. ``[('Set-Cookie', 'foo=abc')]``)
on this request's response.
These headers are suitable for 'remembering' a set of credentials
- implied by the data passed as ``principal`` and ``*kw`` using the
+ implied by the data passed as ``userid`` and ``*kw`` using the
current :term:`authentication policy`. Common usage might look
like so within the body of a view function (``response`` is
assumed to be a :term:`WebOb` -style :term:`response` object
@@ -138,11 +140,28 @@ def remember(request, principal, **kw):
always return an empty sequence. If used, the composition and
meaning of ``**kw`` must be agreed upon by the calling code and
the effective authentication policy.
+
+ .. deprecated:: 1.6
+ Renamed the ``principal`` argument to ``userid`` to clarify its
+ purpose.
"""
+ if userid is _marker:
+ principal = kw.pop('principal', _marker)
+ if principal is _marker:
+ raise TypeError(
+ 'remember() missing 1 required positional argument: '
+ '\'userid\'')
+ else:
+ deprecated(
+ 'principal',
+ 'The "principal" argument was deprecated in Pyramid 1.6. '
+ 'It will be removed in Pyramid 1.9. Use the "userid" '
+ 'argument instead.')
+ userid = principal
policy = _get_authentication_policy(request)
if policy is None:
return []
- return policy.remember(request, principal, **kw)
+ return policy.remember(request, userid, **kw)
def forget(request):
"""
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 8cbd8b82b..f77889e72 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -79,8 +79,8 @@ class DummySecurityPolicy(object):
effective_principals.extend(self.groupids)
return effective_principals
- def remember(self, request, principal, **kw):
- self.remembered = principal
+ def remember(self, request, userid, **kw):
+ self.remembered = userid
return self.remember_result
def forget(self, request):
diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py
index e25e9faa1..c7fc1c211 100644
--- a/pyramid/tests/test_authentication.py
+++ b/pyramid/tests/test_authentication.py
@@ -1211,26 +1211,26 @@ class Test_parse_ticket(unittest.TestCase):
self._assertRaisesBadTicket('secret', ticket, '0.0.0.0')
def test_correct_with_user_data(self):
- ticket = '66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!'
+ ticket = text_('66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!')
result = self._callFUT('secret', ticket, '0.0.0.0')
self.assertEqual(result, (10, 'userid', ['a', 'b'], ''))
def test_correct_with_user_data_sha512(self):
- ticket = '7d947cdef99bad55f8e3382a8bd089bb9dd0547f7925b7d189adc1160cab'\
- '0ec0e6888faa41eba641a18522b26f19109f3ffafb769767ba8a26d02aae'\
- 'ae56599a0000000auserid!a,b!'
+ ticket = text_('7d947cdef99bad55f8e3382a8bd089bb9dd0547f7925b7d189adc1'
+ '160cab0ec0e6888faa41eba641a18522b26f19109f3ffafb769767'
+ 'ba8a26d02aaeae56599a0000000auserid!a,b!')
result = self._callFUT('secret', ticket, '0.0.0.0', 'sha512')
self.assertEqual(result, (10, 'userid', ['a', 'b'], ''))
def test_ipv4(self):
- ticket = 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecdade8d7'\
- '6c530000000auserid!'
+ ticket = text_('b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecd'
+ 'ade8d76c530000000auserid!')
result = self._callFUT('secret', ticket, '198.51.100.1', 'sha256')
self.assertEqual(result, (10, 'userid', [''], ''))
def test_ipv6(self):
- ticket = 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760cd7a2f'\
- 'a4910000000auserid!'
+ ticket = text_('d025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760'
+ 'cd7a2fa4910000000auserid!')
result = self._callFUT('secret', ticket, '2001:db8::1', 'sha256')
self.assertEqual(result, (10, 'userid', [''], ''))
pass
diff --git a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt b/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt
diff --git a/pyramid/tests/test_config/test_assets.py b/pyramid/tests/test_config/test_assets.py
index 345e7f8d6..b605a602d 100644
--- a/pyramid/tests/test_config/test_assets.py
+++ b/pyramid/tests/test_config/test_assets.py
@@ -1,6 +1,10 @@
+import os.path
import unittest
from pyramid.testing import cleanUp
+# we use this folder
+here = os.path.dirname(os.path.abspath(__file__))
+
class TestAssetsConfiguratorMixin(unittest.TestCase):
def _makeOne(self, *arg, **kw):
from pyramid.config import Configurator
@@ -10,27 +14,31 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
def test_override_asset_samename(self):
from pyramid.exceptions import ConfigurationError
config = self._makeOne()
- self.assertRaises(ConfigurationError, config.override_asset,'a', 'a')
+ self.assertRaises(ConfigurationError, config.override_asset, 'a', 'a')
def test_override_asset_directory_with_file(self):
from pyramid.exceptions import ConfigurationError
config = self._makeOne()
self.assertRaises(ConfigurationError, config.override_asset,
- 'a:foo/', 'a:foo.pt')
+ 'a:foo/',
+ 'pyramid.tests.test_config.pkgs.asset:foo.pt')
def test_override_asset_file_with_directory(self):
from pyramid.exceptions import ConfigurationError
config = self._makeOne()
self.assertRaises(ConfigurationError, config.override_asset,
- 'a:foo.pt', 'a:foo/')
+ 'a:foo.pt',
+ 'pyramid.tests.test_config.pkgs.asset:templates/')
def test_override_asset_file_with_package(self):
from pyramid.exceptions import ConfigurationError
config = self._makeOne()
self.assertRaises(ConfigurationError, config.override_asset,
- 'a:foo.pt', 'a')
+ 'a:foo.pt',
+ 'pyramid.tests.test_config.pkgs.asset')
def test_override_asset_file_with_file(self):
+ from pyramid.config.assets import PackageAssetSource
config = self._makeOne(autocommit=True)
override = DummyUnderOverride()
config.override_asset(
@@ -41,10 +49,13 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
from pyramid.tests.test_config.pkgs.asset import subpackage
self.assertEqual(override.package, asset)
self.assertEqual(override.path, 'templates/foo.pt')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, 'templates/bar.pt')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/bar.pt')
def test_override_asset_package_with_package(self):
+ from pyramid.config.assets import PackageAssetSource
config = self._makeOne(autocommit=True)
override = DummyUnderOverride()
config.override_asset(
@@ -55,10 +66,13 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
from pyramid.tests.test_config.pkgs.asset import subpackage
self.assertEqual(override.package, asset)
self.assertEqual(override.path, '')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, '')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, '')
def test_override_asset_directory_with_directory(self):
+ from pyramid.config.assets import PackageAssetSource
config = self._makeOne(autocommit=True)
override = DummyUnderOverride()
config.override_asset(
@@ -69,10 +83,13 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
from pyramid.tests.test_config.pkgs.asset import subpackage
self.assertEqual(override.package, asset)
self.assertEqual(override.path, 'templates/')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/')
def test_override_asset_directory_with_package(self):
+ from pyramid.config.assets import PackageAssetSource
config = self._makeOne(autocommit=True)
override = DummyUnderOverride()
config.override_asset(
@@ -83,10 +100,13 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
from pyramid.tests.test_config.pkgs.asset import subpackage
self.assertEqual(override.package, asset)
self.assertEqual(override.path, 'templates/')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, '')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, '')
def test_override_asset_package_with_directory(self):
+ from pyramid.config.assets import PackageAssetSource
config = self._makeOne(autocommit=True)
override = DummyUnderOverride()
config.override_asset(
@@ -97,32 +117,105 @@ class TestAssetsConfiguratorMixin(unittest.TestCase):
from pyramid.tests.test_config.pkgs.asset import subpackage
self.assertEqual(override.package, asset)
self.assertEqual(override.path, '')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/')
+
+ def test_override_asset_directory_with_absfile(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_asset,
+ 'a:foo/',
+ os.path.join(here, 'pkgs', 'asset', 'foo.pt'))
+
+ def test_override_asset_file_with_absdirectory(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates')
+ self.assertRaises(ConfigurationError, config.override_asset,
+ 'a:foo.pt',
+ abspath)
+
+ def test_override_asset_file_with_missing_abspath(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_asset,
+ 'a:foo.pt',
+ os.path.join(here, 'wont_exist'))
+
+ def test_override_asset_file_with_absfile(self):
+ from pyramid.config.assets import FSAssetSource
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage',
+ 'templates', 'bar.pt')
+ config.override_asset(
+ 'pyramid.tests.test_config.pkgs.asset:templates/foo.pt',
+ abspath,
+ _override=override)
+ from pyramid.tests.test_config.pkgs import asset
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/foo.pt')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
+
+ def test_override_asset_directory_with_absdirectory(self):
+ from pyramid.config.assets import FSAssetSource
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates')
+ config.override_asset(
+ 'pyramid.tests.test_config.pkgs.asset:templates/',
+ abspath,
+ _override=override)
+ from pyramid.tests.test_config.pkgs import asset
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
+
+ def test_override_asset_package_with_absdirectory(self):
+ from pyramid.config.assets import FSAssetSource
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(here, 'pkgs', 'asset', 'subpackage', 'templates')
+ config.override_asset(
+ 'pyramid.tests.test_config.pkgs.asset',
+ abspath,
+ _override=override)
+ from pyramid.tests.test_config.pkgs import asset
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, '')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
def test__override_not_yet_registered(self):
from pyramid.interfaces import IPackageOverrides
package = DummyPackage('package')
- opackage = DummyPackage('opackage')
+ source = DummyAssetSource()
config = self._makeOne()
- config._override(package, 'path', opackage, 'oprefix',
+ config._override(package, 'path', source,
PackageOverrides=DummyPackageOverrides)
overrides = config.registry.queryUtility(IPackageOverrides,
name='package')
- self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
+ self.assertEqual(overrides.inserted, [('path', source)])
self.assertEqual(overrides.package, package)
def test__override_already_registered(self):
from pyramid.interfaces import IPackageOverrides
package = DummyPackage('package')
- opackage = DummyPackage('opackage')
+ source = DummyAssetSource()
overrides = DummyPackageOverrides(package)
config = self._makeOne()
config.registry.registerUtility(overrides, IPackageOverrides,
name='package')
- config._override(package, 'path', opackage, 'oprefix',
+ config._override(package, 'path', source,
PackageOverrides=DummyPackageOverrides)
- self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
+ self.assertEqual(overrides.inserted, [('path', source)])
self.assertEqual(overrides.package, package)
@@ -148,30 +241,24 @@ class TestOverrideProvider(unittest.TestCase):
reg.registerUtility(overrides, IPackageOverrides, name=name)
def test_get_resource_filename_no_overrides(self):
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
expected = os.path.join(here, resource_name)
result = provider.get_resource_filename(None, resource_name)
self.assertEqual(result, expected)
def test_get_resource_stream_no_overrides(self):
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
with provider.get_resource_stream(None, resource_name) as result:
_assertBody(result.read(), os.path.join(here, resource_name))
def test_get_resource_string_no_overrides(self):
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
result = provider.get_resource_string(None, resource_name)
_assertBody(result, os.path.join(here, resource_name))
@@ -202,11 +289,9 @@ class TestOverrideProvider(unittest.TestCase):
def test_get_resource_filename_override_returns_None(self):
overrides = DummyOverrides(None)
self._registerOverrides(overrides)
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
expected = os.path.join(here, resource_name)
result = provider.get_resource_filename(None, resource_name)
self.assertEqual(result, expected)
@@ -214,22 +299,18 @@ class TestOverrideProvider(unittest.TestCase):
def test_get_resource_stream_override_returns_None(self):
overrides = DummyOverrides(None)
self._registerOverrides(overrides)
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
with provider.get_resource_stream(None, resource_name) as result:
_assertBody(result.read(), os.path.join(here, resource_name))
def test_get_resource_string_override_returns_None(self):
overrides = DummyOverrides(None)
self._registerOverrides(overrides)
- import os
resource_name = 'test_assets.py'
import pyramid.tests.test_config
provider = self._makeOne(pyramid.tests.test_config)
- here = os.path.dirname(os.path.abspath(__file__))
result = provider.get_resource_string(None, resource_name)
_assertBody(result, os.path.join(here, resource_name))
@@ -378,8 +459,8 @@ class TestPackageOverrides(unittest.TestCase):
from pyramid.config.assets import DirectoryOverride
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= [None]
- po.insert('foo/', 'package', 'bar/')
+ po.overrides = [None]
+ po.insert('foo/', DummyAssetSource())
self.assertEqual(len(po.overrides), 2)
override = po.overrides[0]
self.assertEqual(override.__class__, DirectoryOverride)
@@ -388,8 +469,8 @@ class TestPackageOverrides(unittest.TestCase):
from pyramid.config.assets import FileOverride
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= [None]
- po.insert('foo.pt', 'package', 'bar.pt')
+ po.overrides = [None]
+ po.insert('foo.pt', DummyAssetSource())
self.assertEqual(len(po.overrides), 2)
override = po.overrides[0]
self.assertEqual(override.__class__, FileOverride)
@@ -399,132 +480,137 @@ class TestPackageOverrides(unittest.TestCase):
from pyramid.config.assets import DirectoryOverride
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= [None]
- po.insert('', 'package', 'bar/')
+ po.overrides = [None]
+ source = DummyAssetSource()
+ po.insert('', source)
self.assertEqual(len(po.overrides), 2)
override = po.overrides[0]
self.assertEqual(override.__class__, DirectoryOverride)
- def test_search_path(self):
- overrides = [ DummyOverride(None), DummyOverride(('package', 'name'))]
+ def test_filtered_sources(self):
+ overrides = [ DummyOverride(None), DummyOverride('foo')]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
- self.assertEqual(list(po.search_path('whatever')),
- [('package', 'name')])
+ po.overrides = overrides
+ self.assertEqual(list(po.filtered_sources('whatever')), ['foo'])
def test_get_filename(self):
- import os
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'test_assets.py'))]
+ source = DummyAssetSource(filename='foo.pt')
+ overrides = [ DummyOverride(None), DummyOverride((source, ''))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
- here = os.path.dirname(os.path.abspath(__file__))
- expected = os.path.join(here, 'test_assets.py')
- self.assertEqual(po.get_filename('whatever'), expected)
+ po.overrides = overrides
+ result = po.get_filename('whatever')
+ self.assertEqual(result, 'foo.pt')
+ self.assertEqual(source.resource_name, '')
def test_get_filename_file_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(filename=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.get_filename('whatever'), None)
-
+ self.assertEqual(source.resource_name, 'wont_exist')
+
def test_get_stream(self):
- import os
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'test_assets.py'))]
+ source = DummyAssetSource(stream='a stream?')
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
- here = os.path.dirname(os.path.abspath(__file__))
- with po.get_stream('whatever') as stream:
- _assertBody(stream.read(), os.path.join(here, 'test_assets.py'))
+ po.overrides = overrides
+ self.assertEqual(po.get_stream('whatever'), 'a stream?')
+ self.assertEqual(source.resource_name, 'foo.pt')
def test_get_stream_file_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(stream=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.get_stream('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
def test_get_string(self):
- import os
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'test_assets.py'))]
+ source = DummyAssetSource(string='a string')
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
- here = os.path.dirname(os.path.abspath(__file__))
- _assertBody(po.get_string('whatever'),
- os.path.join(here, 'test_assets.py'))
+ po.overrides = overrides
+ self.assertEqual(po.get_string('whatever'), 'a string')
+ self.assertEqual(source.resource_name, 'foo.pt')
def test_get_string_file_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(string=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.get_string('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
def test_has_resource(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'test_assets.py'))]
+ source = DummyAssetSource(exists=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.has_resource('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
def test_has_resource_file_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(exists=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.has_resource('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
def test_isdir_false(self):
- overrides = [ DummyOverride(
- ('pyramid.tests.test_config', 'test_assets.py'))]
+ source = DummyAssetSource(isdir=False)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.isdir('whatever'), False)
-
+ self.assertEqual(source.resource_name, 'foo.pt')
+
def test_isdir_true(self):
- overrides = [ DummyOverride(
- ('pyramid.tests.test_config', 'files'))]
+ source = DummyAssetSource(isdir=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.isdir('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
def test_isdir_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(isdir=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.isdir('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
def test_listdir(self):
- overrides = [ DummyOverride(
- ('pyramid.tests.test_config', 'files'))]
+ source = DummyAssetSource(listdir=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
- self.assertTrue(po.listdir('whatever'))
+ po.overrides = overrides
+ self.assertEqual(po.listdir('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
def test_listdir_doesnt_exist(self):
- overrides = [ DummyOverride(None), DummyOverride(
- ('pyramid.tests.test_config', 'wont_exist'))]
+ source = DummyAssetSource(listdir=None)
+ overrides = [DummyOverride(None), DummyOverride((source, 'wont_exist'))]
package = DummyPackage('package')
po = self._makeOne(package)
- po.overrides= overrides
+ po.overrides = overrides
self.assertEqual(po.listdir('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
# PEP 302 __loader__ extensions: use the "real" __loader__, if present.
def test_get_data_pkg_has_no___loader__(self):
@@ -570,27 +656,124 @@ class TestPackageOverrides(unittest.TestCase):
def test_get_source_pkg_has___loader__(self):
package = DummyPackage('package')
- loader = package.__loader__ = DummyLoader()
+ loader = package.__loader__ = DummyLoader()
po = self._makeOne(package)
self.assertEqual(po.get_source('whatever'), 'def foo():\n pass')
self.assertEqual(loader._got_source, 'whatever')
+class AssetSourceIntegrationTests(object):
+
+ def test_get_filename(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_filename('test_assets.py'),
+ os.path.join(here, 'test_assets.py'))
+
+ def test_get_filename_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ self.assertEqual(source.get_filename(''),
+ os.path.join(here, 'test_assets.py'))
+
+ def test_get_filename_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_filename('wont_exist'), None)
+
+ def test_get_stream(self):
+ source = self._makeOne('')
+ with source.get_stream('test_assets.py') as stream:
+ _assertBody(stream.read(), os.path.join(here, 'test_assets.py'))
+
+ def test_get_stream_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ with source.get_stream('') as stream:
+ _assertBody(stream.read(), os.path.join(here, 'test_assets.py'))
+
+ def test_get_stream_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_stream('wont_exist'), None)
+
+ def test_get_string(self):
+ source = self._makeOne('')
+ _assertBody(source.get_string('test_assets.py'),
+ os.path.join(here, 'test_assets.py'))
+
+ def test_get_string_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ _assertBody(source.get_string(''),
+ os.path.join(here, 'test_assets.py'))
+
+ def test_get_string_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_string('wont_exist'), None)
+
+ def test_exists(self):
+ source = self._makeOne('')
+ self.assertEqual(source.exists('test_assets.py'), True)
+
+ def test_exists_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ self.assertEqual(source.exists(''), True)
+
+ def test_exists_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.exists('wont_exist'), None)
+
+ def test_isdir_false(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('test_assets.py'), False)
+
+ def test_isdir_true(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('files'), True)
+
+ def test_isdir_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('wont_exist'), None)
+
+ def test_listdir(self):
+ source = self._makeOne('')
+ self.assertTrue(source.listdir('files'))
+
+ def test_listdir_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.listdir('wont_exist'), None)
+
+class TestPackageAssetSource(AssetSourceIntegrationTests, unittest.TestCase):
+
+ def _getTargetClass(self):
+ from pyramid.config.assets import PackageAssetSource
+ return PackageAssetSource
+
+ def _makeOne(self, prefix, package='pyramid.tests.test_config'):
+ klass = self._getTargetClass()
+ return klass(package, prefix)
+
+class TestFSAssetSource(AssetSourceIntegrationTests, unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import FSAssetSource
+ return FSAssetSource
+
+ def _makeOne(self, prefix, base_prefix=here):
+ klass = self._getTargetClass()
+ return klass(os.path.join(base_prefix, prefix))
+
class TestDirectoryOverride(unittest.TestCase):
def _getTargetClass(self):
from pyramid.config.assets import DirectoryOverride
return DirectoryOverride
- def _makeOne(self, path, package, prefix):
+ def _makeOne(self, path, source):
klass = self._getTargetClass()
- return klass(path, package, prefix)
+ return klass(path, source)
def test_it_match(self):
- o = self._makeOne('foo/', 'package', 'bar/')
+ source = DummyAssetSource()
+ o = self._makeOne('foo/', source)
result = o('foo/something.pt')
- self.assertEqual(result, ('package', 'bar/something.pt'))
+ self.assertEqual(result, (source, 'something.pt'))
def test_it_no_match(self):
- o = self._makeOne('foo/', 'package', 'bar/')
+ source = DummyAssetSource()
+ o = self._makeOne('foo/', source)
result = o('baz/notfound.pt')
self.assertEqual(result, None)
@@ -599,17 +782,19 @@ class TestFileOverride(unittest.TestCase):
from pyramid.config.assets import FileOverride
return FileOverride
- def _makeOne(self, path, package, prefix):
+ def _makeOne(self, path, source):
klass = self._getTargetClass()
- return klass(path, package, prefix)
+ return klass(path, source)
def test_it_match(self):
- o = self._makeOne('foo.pt', 'package', 'bar.pt')
+ source = DummyAssetSource()
+ o = self._makeOne('foo.pt', source)
result = o('foo.pt')
- self.assertEqual(result, ('package', 'bar.pt'))
+ self.assertEqual(result, (source, ''))
def test_it_no_match(self):
- o = self._makeOne('foo.pt', 'package', 'bar.pt')
+ source = DummyAssetSource()
+ o = self._makeOne('foo.pt', source)
result = o('notfound.pt')
self.assertEqual(result, None)
@@ -634,8 +819,8 @@ class DummyPackageOverrides:
self.package = package
self.inserted = []
- def insert(self, path, package, prefix):
- self.inserted.append((path, package, prefix))
+ def insert(self, path, source):
+ self.inserted.append((path, source))
class DummyPkgResources:
def __init__(self):
@@ -647,6 +832,34 @@ class DummyPkgResources:
class DummyPackage:
def __init__(self, name):
self.__name__ = name
+
+class DummyAssetSource:
+ def __init__(self, **kw):
+ self.kw = kw
+
+ def get_filename(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['filename']
+
+ def get_stream(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['stream']
+
+ def get_string(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['string']
+
+ def exists(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['exists']
+
+ def isdir(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['isdir']
+
+ def listdir(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['listdir']
class DummyLoader:
_got_data = _is_package = None
@@ -664,12 +877,10 @@ class DummyLoader:
return 'def foo():\n pass'
class DummyUnderOverride:
- def __call__(self, package, path, override_package, override_prefix,
- _info=''):
+ def __call__(self, package, path, source, _info=''):
self.package = package
self.path = path
- self.override_package = override_package
- self.override_prefix = override_prefix
+ self.source = source
def read_(src):
with open(src, 'rb') as f:
diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py
index 39b8ba70d..b0d03fb72 100644
--- a/pyramid/tests/test_config/test_views.py
+++ b/pyramid/tests/test_config/test_views.py
@@ -3898,6 +3898,13 @@ class TestStaticURLInfo(unittest.TestCase):
('http://example.com/', 'anotherpackage:path/', None, None)]
self._assertRegistrations(config, expected)
+ def test_add_package_root(self):
+ inst = self._makeOne()
+ config = self._makeConfig()
+ inst.add(config, 'http://example.com', 'package:')
+ expected = [('http://example.com/', 'package:', None, None)]
+ self._assertRegistrations(config, expected)
+
def test_add_url_withendslash(self):
inst = self._makeOne()
config = self._makeConfig()
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index 35648ed38..c2786c391 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -81,7 +81,7 @@ class StaticAppBase(IntegrationBase):
res = self.testapp.get('/static/.hiddenfile', status=200)
_assertBody(res.body, os.path.join(here, 'fixtures/static/.hiddenfile'))
- if defaultlocale is not None:
+ if defaultlocale is not None: # pragma: no cover
# These tests are expected to fail on LANG=C systems due to decode
# errors and on non-Linux systems due to git highchar handling
# vagaries
diff --git a/pyramid/tests/test_registry.py b/pyramid/tests/test_registry.py
index 11019b852..50f49f24d 100644
--- a/pyramid/tests/test_registry.py
+++ b/pyramid/tests/test_registry.py
@@ -12,6 +12,11 @@ class TestRegistry(unittest.TestCase):
registry = self._makeOne()
self.assertEqual(registry.__nonzero__(), True)
+ def test_package_name(self):
+ package_name = 'testing'
+ registry = self._getTargetClass()(package_name)
+ self.assertEqual(registry.package_name, package_name)
+
def test_registerHandler_and_notify(self):
registry = self._makeOne()
self.assertEqual(registry.has_listeners, False)
diff --git a/pyramid/tests/test_scripts/pystartup.py b/pyramid/tests/test_scripts/pystartup.py
new file mode 100644
index 000000000..c4e5bcc80
--- /dev/null
+++ b/pyramid/tests/test_scripts/pystartup.py
@@ -0,0 +1 @@
+foo = 1
diff --git a/pyramid/tests/test_scripts/test_proutes.py b/pyramid/tests/test_scripts/test_proutes.py
index 25a3cd2e3..32202af4b 100644
--- a/pyramid/tests/test_scripts/test_proutes.py
+++ b/pyramid/tests/test_scripts/test_proutes.py
@@ -123,8 +123,53 @@ class TestPRoutesCommand(unittest.TestCase):
self.assertEqual(result, 0)
self.assertEqual(len(L), 3)
compare_to = L[-1].split()[:3]
- self.assertEqual(compare_to, ['a', '/a', '<function'])
-
+ self.assertEqual(
+ compare_to,
+ ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']
+ )
+
+ def test_one_route_with_long_name_one_view_registered(self):
+ from zope.interface import Interface
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+ registry = Registry()
+ def view():pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerAdapter(
+ view,
+ (IViewClassifier, IMyRoute, Interface),
+ IView, ''
+ )
+
+ registry.registerUtility(IMyRoute, IRouteRequest,
+ name='very_long_name_123')
+
+ command = self._makeOne()
+ route = dummy.DummyRoute(
+ 'very_long_name_123',
+ '/and_very_long_pattern_as_well'
+ )
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = (dummy.DummyBootstrap(registry=registry),)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()[:3]
+ self.assertEqual(
+ compare_to,
+ ['very_long_name_123',
+ '/and_very_long_pattern_as_well',
+ 'pyramid.tests.test_scripts.test_proutes.view']
+ )
+
def test_single_route_one_view_registered_with_factory(self):
from zope.interface import Interface
from pyramid.registry import Registry
@@ -154,6 +199,47 @@ class TestPRoutesCommand(unittest.TestCase):
self.assertEqual(len(L), 3)
self.assertEqual(L[-1].split()[:3], ['a', '/a', '<unknown>'])
+ def test_single_route_multiview_registered(self):
+ from zope.interface import Interface
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ registry = Registry()
+
+ def view(): pass
+
+ class IMyRoute(Interface):
+ pass
+
+ multiview1 = dummy.DummyMultiView(
+ view, context='context',
+ view_name='a1'
+ )
+
+ registry.registerAdapter(
+ multiview1,
+ (IViewClassifier, IMyRoute, Interface),
+ IMultiView, ''
+ )
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = (dummy.DummyBootstrap(registry=registry),)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()[:3]
+ self.assertEqual(
+ compare_to,
+ ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']
+ )
+
def test__get_mapper(self):
from pyramid.registry import Registry
from pyramid.urldispatch import RoutesMapper
@@ -161,7 +247,7 @@ class TestPRoutesCommand(unittest.TestCase):
registry = Registry()
result = command._get_mapper(registry)
self.assertEqual(result.__class__, RoutesMapper)
-
+
class Test_main(unittest.TestCase):
def _callFUT(self, argv):
from pyramid.scripts.proutes import main
@@ -170,4 +256,3 @@ class Test_main(unittest.TestCase):
def test_it(self):
result = self._callFUT(['proutes'])
self.assertEqual(result, 2)
-
diff --git a/pyramid/tests/test_scripts/test_pshell.py b/pyramid/tests/test_scripts/test_pshell.py
index 7cb130c41..a6ba2eaea 100644
--- a/pyramid/tests/test_scripts/test_pshell.py
+++ b/pyramid/tests/test_scripts/test_pshell.py
@@ -1,3 +1,4 @@
+import os
import unittest
from pyramid.tests.test_scripts import dummy
@@ -24,6 +25,9 @@ class TestPShellCommand(unittest.TestCase):
self.options.python_shell = ''
self.options.setup = None
cmd.options = self.options
+ # default to None to prevent side-effects from running tests in
+ # unknown environments
+ cmd.pystartup = None
return cmd
def test_make_default_shell(self):
@@ -369,6 +373,25 @@ class TestPShellCommand(unittest.TestCase):
self.assertTrue(self.bootstrap.closer.called)
self.assertTrue(shell.help)
+ def test_command_loads_pythonstartup(self):
+ command = self._makeOne()
+ command.pystartup = (
+ os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ 'pystartup.py')))
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(shell.env, {
+ 'app':self.bootstrap.app, 'root':self.bootstrap.root,
+ 'registry':self.bootstrap.registry,
+ 'request':self.bootstrap.request,
+ 'root_factory':self.bootstrap.root_factory,
+ 'foo':1,
+ })
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
class Test_main(unittest.TestCase):
def _callFUT(self, argv):
diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py
index 6f08a100c..6d75ac8e3 100644
--- a/pyramid/tests/test_security.py
+++ b/pyramid/tests/test_security.py
@@ -134,9 +134,9 @@ class TestRemember(unittest.TestCase):
def tearDown(self):
testing.tearDown()
- def _callFUT(self, *arg):
+ def _callFUT(self, *arg, **kwarg):
from pyramid.security import remember
- return remember(*arg)
+ return remember(*arg, **kwarg)
def test_no_authentication_policy(self):
request = _makeRequest()
@@ -159,6 +159,19 @@ class TestRemember(unittest.TestCase):
result = self._callFUT(request, 'me')
self.assertEqual(result, [('X-Pyramid-Test', 'me')])
+ def test_with_deprecated_principal_arg(self):
+ request = _makeRequest()
+ registry = request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ result = self._callFUT(request, principal='me')
+ self.assertEqual(result, [('X-Pyramid-Test', 'me')])
+
+ def test_with_missing_arg(self):
+ request = _makeRequest()
+ registry = request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ self.assertRaises(TypeError, lambda: self._callFUT(request))
+
class TestForget(unittest.TestCase):
def setUp(self):
testing.setUp()
@@ -462,8 +475,8 @@ class DummyAuthenticationPolicy:
def authenticated_userid(self, request):
return self.result
- def remember(self, request, principal, **kw):
- headers = [(_TEST_HEADER, principal)]
+ def remember(self, request, userid, **kw):
+ headers = [(_TEST_HEADER, userid)]
self._header_remembered = headers[0]
return headers
diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py
index 2ca4c4a66..a18fa8d16 100644
--- a/pyramid/tests/test_util.py
+++ b/pyramid/tests/test_util.py
@@ -217,6 +217,49 @@ class Test_WeakOrderedSet(unittest.TestCase):
self.assertEqual(list(wos), [])
self.assertEqual(wos.last, None)
+class Test_strings_differ(unittest.TestCase):
+ def _callFUT(self, *args, **kw):
+ from pyramid.util import strings_differ
+ return strings_differ(*args, **kw)
+
+ def test_it(self):
+ self.assertFalse(self._callFUT(b'foo', b'foo'))
+ self.assertTrue(self._callFUT(b'123', b'345'))
+ self.assertTrue(self._callFUT(b'1234', b'123'))
+ self.assertTrue(self._callFUT(b'123', b'1234'))
+
+ def test_it_with_internal_comparator(self):
+ result = self._callFUT(b'foo', b'foo', compare_digest=None)
+ self.assertFalse(result)
+
+ result = self._callFUT(b'123', b'abc', compare_digest=None)
+ self.assertTrue(result)
+
+ def test_it_with_external_comparator(self):
+ class DummyComparator(object):
+ called = False
+ def __init__(self, ret_val):
+ self.ret_val = ret_val
+
+ def __call__(self, a, b):
+ self.called = True
+ return self.ret_val
+
+ dummy_compare = DummyComparator(True)
+ result = self._callFUT(b'foo', b'foo', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertFalse(result)
+
+ dummy_compare = DummyComparator(False)
+ result = self._callFUT(b'123', b'345', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertTrue(result)
+
+ dummy_compare = DummyComparator(False)
+ result = self._callFUT(b'abc', b'abc', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertTrue(result)
+
class Test_object_description(unittest.TestCase):
def _callFUT(self, object):
from pyramid.util import object_description
diff --git a/pyramid/util.py b/pyramid/util.py
index 6b92f17fc..6de53d559 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -1,4 +1,9 @@
import functools
+try:
+ # py2.7.7+ and py3.3+ have native comparison support
+ from hmac import compare_digest
+except ImportError: # pragma: nocover
+ compare_digest = None
import inspect
import traceback
import weakref
@@ -227,7 +232,7 @@ class WeakOrderedSet(object):
oid = self._order[-1]
return self._items[oid]()
-def strings_differ(string1, string2):
+def strings_differ(string1, string2, compare_digest=compare_digest):
"""Check whether two strings differ while avoiding timing attacks.
This function returns True if the given strings differ and False
@@ -237,14 +242,25 @@ def strings_differ(string1, string2):
http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf
- """
- if len(string1) != len(string2):
- return True
-
- invalid_bits = 0
- for a, b in zip(string1, string2):
- invalid_bits += a != b
+ .. versionchanged:: 1.6
+ Support :func:`hmac.compare_digest` if it is available (Python 2.7.7+
+ and Python 3.3+).
+ """
+ len_eq = len(string1) == len(string2)
+ if len_eq:
+ invalid_bits = 0
+ left = string1
+ else:
+ invalid_bits = 1
+ left = string2
+ right = string2
+
+ if compare_digest is not None:
+ invalid_bits += not compare_digest(left, right)
+ else:
+ for a, b in zip(left, right):
+ invalid_bits += a != b
return invalid_bits != 0
def object_description(object):
diff --git a/setup.cfg b/setup.cfg
index a877ffb7f..9633b6980 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,6 +7,7 @@ where=pyramid
nocapture=1
cover-package=pyramid
cover-erase=1
+cover-min-percentage=100
[aliases]
dev = develop easy_install pyramid[testing]
diff --git a/tox.ini b/tox.ini
index 2bf213ca4..714c5b6d3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
envlist =
- py26,py27,py32,py33,py34,pypy,cover
+ py26,py27,py32,py33,py34,pypy,pypy3,cover
[testenv]
commands =